From 63ccea18754d2737f316eb50c680e38e5f1366b9 Mon Sep 17 00:00:00 2001 From: Greg Ferrell Date: Thu, 18 Sep 2014 21:37:04 -0700 Subject: [PATCH 001/593] Update README.md Fixed typo: "future prove" --> "future-proof" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 365a4bb1..45b9a7e2 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ to the masses. ## Contribution We are looking for people who share the idea of having a simple, flexible charting library that is responsive and uses -modern and future prove technologies. The goal of this project is to create a responsive charting library where developers +modern and future-proof technologies. The goal of this project is to create a responsive charting library where developers have their joy in using it and designers love it because of the designing flexibility they have. Contribute if you like the Chartist Guy! From 0889ef63d94f7d9bc3a295e7d362ef518b13a9e3 Mon Sep 17 00:00:00 2001 From: Tom Robertshaw Date: Sat, 20 Sep 2014 13:11:36 +0100 Subject: [PATCH 002/593] Minor typo fix on getting started page. --- source/site/data/pages/getting-started.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/site/data/pages/getting-started.yml b/source/site/data/pages/getting-started.yml index 8fd5f285..bea403d2 100644 --- a/source/site/data/pages/getting-started.yml +++ b/source/site/data/pages/getting-started.yml @@ -32,7 +32,7 @@ sections: data: text: > The quickest way to get things up and running is by using the Chartist.js CSS files. - The CSS is compiled from the SASS files with de default class names which are also + The CSS is compiled from the SASS files with the default class names which are also configured in the JavaScript library. You can then override the default styles or modify the CSS file, however, for customization it's recommended to use the SASS version of Chartist.js. @@ -375,4 +375,4 @@ sections: data: id: behavior-with-jquery classes: ct-golden-section - show-code-button: Show code \ No newline at end of file + show-code-button: Show code From c31f4f971a83bb3aa703076f91ddb5568f28bc88 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 22 Sep 2014 14:12:33 +0200 Subject: [PATCH 003/593] Changed bower update to to bower install --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6fca7ce..bfbbf637 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ You will need the following to run a local development enviroment. 1. `cd` into your local copy of the repository. 2. Run `npm install` to install dependencies located in `package.json`. -3. Run `bower update` to install bower dependencies. +3. Run `bower install` to install bower dependencies. 5. Run `grunt serve` to start the watch task, and the web server should automatically open. Congrats, you should now be able to see your local copy of the demo site. ## Submission Guidelines From 73c83d108c2f316d566ec95d15bc6511ce5bf125 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 26 Sep 2014 00:33:29 +0200 Subject: [PATCH 004/593] Added simple area shape functionality to the line chart --- source/scripts/chartist.line.js | 48 +++++++++++++++---- source/site/data/pages/examples.yml | 20 ++++++++ .../examples/example-bipolar-line-area.js | 19 ++++++++ source/site/examples/example-line-area.js | 9 ++++ source/styles/chartist.scss | 11 ++++- .../styles/settings/_chartist-settings.scss | 3 ++ 6 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 source/site/examples/example-bipolar-line-area.js create mode 100644 source/site/examples/example-line-area.js diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index b737fef3..e9059d92 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -56,6 +56,10 @@ * showLine: true, * // If dots should be drawn or not * showPoint: true, + * // If the line chart should draw an area + * showArea: false, + * // The base for the area chart that will be used to close the area shape (is normally 0) + * areaBase: 0, * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) * lineSmooth: true, * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value @@ -71,6 +75,7 @@ * series: 'ct-series', * line: 'ct-line', * point: 'ct-point', + * area: 'ct-area', * grid: 'ct-grid', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' @@ -155,6 +160,8 @@ height: undefined, showLine: true, showPoint: true, + showArea: false, + areaBase: 0, lineSmooth: true, low: undefined, high: undefined, @@ -165,6 +172,7 @@ series: 'ct-series', line: 'ct-line', point: 'ct-point', + area: 'ct-area', grid: 'ct-grid', vertical: 'ct-vertical', horizontal: 'ct-horizontal' @@ -257,27 +265,49 @@ } } - if (options.showLine) { - var svgPathString = 'M' + pathCoordinates[0] + ',' + pathCoordinates[1] + ' '; + // TODO: Nicer handling of conditions, maybe composition? + if (options.showLine || options.showArea) { + // TODO: We should add a path API in the SVG library for easier path creation + var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; // If smoothed path and path has more than two points then use catmull rom to bezier algorithm if (options.lineSmooth && pathCoordinates.length > 4) { var cr = Chartist.catmullRom2bezier(pathCoordinates); for(var k = 0; k < cr.length; k++) { - svgPathString += 'C' + cr[k].join(); + pathElements.push('C' + cr[k].join()); } } else { for(var l = 3; l < pathCoordinates.length; l += 2) { - svgPathString += 'L ' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]; + pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); } } - seriesGroups[i].elem('path', { - d: svgPathString - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); + if(options.showArea) { + // If we need to draw area shapes we just make a copy of our pathElements SVG path array + var areaPathElements = pathElements.slice(); + // We project the areaBase value into screen coordinates + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0); + // And splice our new area path array to add the missing path elements to close the area shape + areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); + areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; + areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + + // Create the new path for the area shape with the area class from the options + seriesGroups[i].elem('path', { + d: areaPathElements.join('') + }, options.classNames.area, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } + + if(options.showLine) { + seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } } } } diff --git a/source/site/data/pages/examples.yml b/source/site/data/pages/examples.yml index 7f8b2297..6c25ac7e 100644 --- a/source/site/data/pages/examples.yml +++ b/source/site/data/pages/examples.yml @@ -29,6 +29,26 @@ sections: Adding behavior to your chart with JavaScript is a breeze and is just like any other DOM manipulation you do to your site. This is just one of many benefits of using inline-SVG and provides you with the freedom you need in order to create exactly the experience you're looking for. + - type: live-example + data: + title: Line chart with area + level: 4 + id: example-line-area + classes: ct-golden-section + intro: > + This chart uses the showArea option to draw line, dots but also an area shape. Use the low option to + specify a fixed lower bound that will make the area expand. You can also use the areaBase property + to specify a data value that will be used to determine the area shap base position (this is 0 by default). + - type: live-example + data: + title: Bi-polar Line chart with area only + level: 4 + id: example-bipolar-line-area + classes: ct-golden-section + intro: > + You can also only draw the area shapes of the line chart. Area shapes will always be constructed around + their areaBase (that can be configured in the options) which also allows you to draw nice bi-polar + areas. - title: Bar chart examples level: 3 items: diff --git a/source/site/examples/example-bipolar-line-area.js b/source/site/examples/example-bipolar-line-area.js new file mode 100644 index 00000000..00c65822 --- /dev/null +++ b/source/site/examples/example-bipolar-line-area.js @@ -0,0 +1,19 @@ +Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8], + series: [ + [1, 2, 3, 1, -2, 0, 1, 0], + [-2, -1, -2, -1, -2.5, -1, -2, -1], + [0, 0, 0, 1, 2, 2.5, 2, 1], + [2.5, 2, 1, 0.5, 1, 0.5, -1, -2.5] + ] +}, { + high: 3, + low: -3, + showArea: true, + showLine: false, + showPoint: false, + axisX: { + showLabel: false, + showGrid: false + } +}); \ No newline at end of file diff --git a/source/site/examples/example-line-area.js b/source/site/examples/example-line-area.js new file mode 100644 index 00000000..3b1ae568 --- /dev/null +++ b/source/site/examples/example-line-area.js @@ -0,0 +1,9 @@ +Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8], + series: [ + [5, 9, 7, 8, 5, 3, 5, 4] + ] +}, { + low: 0, + showArea: true +}); \ No newline at end of file diff --git a/source/styles/chartist.scss b/source/styles/chartist.scss index a9fb7498..e7b6699a 100644 --- a/source/styles/chartist.scss +++ b/source/styles/chartist.scss @@ -59,6 +59,11 @@ } } +@mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) { + stroke: none; + fill-opacity: $ct-area-opacity; +} + @mixin ct-chart-bar($ct-bar-width: $ct-bar-width) { fill: none; stroke-width: $ct-bar-width; @@ -74,7 +79,7 @@ stroke: $color; } - .#{$ct-class-slice}:not(.#{$ct-class-donut}) { + .#{$ct-class-slice}:not(.#{$ct-class-donut}), .#{$ct-class-area} { fill: $color; } } @@ -96,6 +101,10 @@ @include ct-chart-line($ct-line-width); } + .#{$ct-class-area} { + @include ct-chart-area(); + } + .#{$ct-class-bar} { @include ct-chart-bar($ct-bar-width); } diff --git a/source/styles/settings/_chartist-settings.scss b/source/styles/settings/_chartist-settings.scss index b96888da..51f69d1d 100644 --- a/source/styles/settings/_chartist-settings.scss +++ b/source/styles/settings/_chartist-settings.scss @@ -11,6 +11,7 @@ $ct-class-label: ct-label !default; $ct-class-series: ct-series !default; $ct-class-line: ct-line !default; $ct-class-point: ct-point !default; +$ct-class-area: ct-area !default; $ct-class-bar: ct-bar !default; $ct-class-slice: ct-slice !default; $ct-class-donut: ct-donut !default; @@ -36,6 +37,8 @@ $ct-line-dasharray: false !default; $ct-point-size: 10px !default; // Line chart point, can be either round or square $ct-point-shape: round !default; +// Area fill transparency between 0 and 1 +$ct-area-opacity: 0.1 !default; // Bar chart bar width $ct-bar-width: 10px !default; From 8e1bf71eeb4a649d146d73f1093eec8325bee1cc Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 26 Sep 2014 00:35:02 +0200 Subject: [PATCH 005/593] Version 0.1.15 and libdist --- bower.json | 2 +- libdist/chartist.js | 50 +++++++++++++++---- libdist/chartist.min.css | 4 +- libdist/chartist.min.js | 4 +- libdist/chartist.min.map | 2 +- libdist/scss/chartist.scss | 11 +++- libdist/scss/settings/_chartist-settings.scss | 3 ++ package.json | 2 +- 8 files changed, 60 insertions(+), 18 deletions(-) diff --git a/bower.json b/bower.json index 99dc4c80..f117c6aa 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.1.14", + "version": "0.1.15", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index 26136b9d..26afd98f 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.1.14 + /* Chartist.js 0.1.15 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -827,6 +827,10 @@ * showLine: true, * // If dots should be drawn or not * showPoint: true, + * // If the line chart should draw an area + * showArea: false, + * // The base for the area chart that will be used to close the area shape (is normally 0) + * areaBase: 0, * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) * lineSmooth: true, * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value @@ -842,6 +846,7 @@ * series: 'ct-series', * line: 'ct-line', * point: 'ct-point', + * area: 'ct-area', * grid: 'ct-grid', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' @@ -926,6 +931,8 @@ height: undefined, showLine: true, showPoint: true, + showArea: false, + areaBase: 0, lineSmooth: true, low: undefined, high: undefined, @@ -936,6 +943,7 @@ series: 'ct-series', line: 'ct-line', point: 'ct-point', + area: 'ct-area', grid: 'ct-grid', vertical: 'ct-vertical', horizontal: 'ct-horizontal' @@ -1028,27 +1036,49 @@ } } - if (options.showLine) { - var svgPathString = 'M' + pathCoordinates[0] + ',' + pathCoordinates[1] + ' '; + // TODO: Nicer handling of conditions, maybe composition? + if (options.showLine || options.showArea) { + // TODO: We should add a path API in the SVG library for easier path creation + var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; // If smoothed path and path has more than two points then use catmull rom to bezier algorithm if (options.lineSmooth && pathCoordinates.length > 4) { var cr = Chartist.catmullRom2bezier(pathCoordinates); for(var k = 0; k < cr.length; k++) { - svgPathString += 'C' + cr[k].join(); + pathElements.push('C' + cr[k].join()); } } else { for(var l = 3; l < pathCoordinates.length; l += 2) { - svgPathString += 'L ' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]; + pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); } } - seriesGroups[i].elem('path', { - d: svgPathString - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); + if(options.showArea) { + // If we need to draw area shapes we just make a copy of our pathElements SVG path array + var areaPathElements = pathElements.slice(); + // We project the areaBase value into screen coordinates + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0); + // And splice our new area path array to add the missing path elements to close the area shape + areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); + areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; + areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + + // Create the new path for the area shape with the area class from the options + seriesGroups[i].elem('path', { + d: areaPathElements.join('') + }, options.classNames.area, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } + + if(options.showLine) { + seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } } } } diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index 4edd5c45..2b2b5218 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,7 +1,7 @@ -/* Chartist.js 0.1.14 +/* Chartist.js 0.1.15 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -.ct-chart .ct-label{fill:rgba(0,0,0,.4);font-size:.75rem}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.88889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.33333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.66667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.8047%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.33333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.33333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%} \ No newline at end of file +.ct-chart .ct-label{fill:rgba(0,0,0,.4);font-size:.75rem}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.88889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.33333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.66667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.8047%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.33333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.33333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%} \ No newline at end of file diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 821b7174..8732fc25 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.1.14 +/* Chartist.js 0.1.15 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.1.14",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getHeight=function(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight},c.getWidth=function(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b||"100%",height:d||"100%"}).removeAllClasses().addClass(e),f.empty()):(f=c.svg("svg").attr({width:b||"100%",height:d||"100%"}).addClass(e),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return c.getHeight(a._node)-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e])}),a}function i(a,d,e,f,g,i){var j=b.createElementNS(q,d);return"svg"===d&&j.setAttributeNS(r,c.xmlNs.qualifiedName,c.xmlNs.uri),i&&(g&&i.firstChild?i.insertBefore(j,i.firstChild):i.appendChild(j)),e&&h(j,e),f&&n(j,f),j}function j(a,c){a.appendChild(b.createTextNode(c))}function k(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function l(a){a.parentNode.removeChild(a)}function m(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function n(a,b){a.setAttribute("class",m(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function o(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",m(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function p(a){a.setAttribute("class","")}var q="http://www.w3.org/2000/svg",r="http://www.w3.org/2000/xmlns/";return{_node:i(this,a,d,e,f,g?g._node:void 0),_parent:g,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return k(this._node),this},remove:function(){return l(this._node),this},elem:function(a,b,d,e){return c.svg(a,b,d,e,this)},text:function(a){return j(this._node,a),this},addClass:function(a){return n(this._node,a),this},removeClass:function(a){return o(this._node,a),this},removeAllClasses:function(){return p(this._node),this},classes:function(){return m(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);n=c.createSvg(p,a.width,a.height,a.classNames.chart),f=c.getBounds(n,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(n,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,c.getHeight)),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(n,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,c.getWidth));var i=c.createChartRect(n,a,b,e),j=n.elem("g"),k=n.elem("g");c.createXAxis(i,d,k,j,a),c.createYAxis(i,f,k,j,e,a);for(var l=0;l4)for(var t=c.catmullRom2bezier(q),u=0;ua.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);o=c.createSvg(q,a.width,a.height,a.classNames.chart),b=c.createChartRect(o,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=0;m=n-j?"0":"1",t=["M",r.x,r.y,"A",e,e,0,s,0,p.x,p.y];a.donut===!1&&t.push("L",l.x,l.y);var u=i[m].elem("path",{d:t.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(u.attr({value:k[m]},c.xmlNs.uri),a.donut===!0&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),a.showLabel){var v=c.polarToCartesian(l.x,l.y,f,j+(n-j)/2),w=a.labelInterpolationFnc(d.labels?d.labels[m]:k[m],m);i[m].elem("text",{dx:v.x,dy:v.y,"text-anchor":g(l,v,a.labelDirection)},a.classNames.label).text(""+w)}j=n}}function i(){h(n.currentOptions)}function j(){a.removeEventListener("resize",i),n.clear()}function k(a){n.addOptionsListener(a)}function l(a){n.removeOptionsListener(a)}function m(){h(n.currentOptions)}var n,o,p={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},q=c.querySelector(b);q.chartist&&q.chartist.detach(),n=c.optionsProvider(p,e,f),h(n.currentOptions),a.addEventListener("resize",m);var r={version:c.version,update:i,detach:j,addOptionsListener:k,removeOptionsListener:l};return q.chartist=r,r}}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.1.14",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getHeight=function(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight},c.getWidth=function(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b||"100%",height:d||"100%"}).removeAllClasses().addClass(e),f.empty()):(f=c.svg("svg").attr({width:b||"100%",height:d||"100%"}).addClass(e),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return c.getHeight(a._node)-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e])}),a}function i(a,d,e,f,g,i){var j=b.createElementNS(q,d);return"svg"===d&&j.setAttributeNS(r,c.xmlNs.qualifiedName,c.xmlNs.uri),i&&(g&&i.firstChild?i.insertBefore(j,i.firstChild):i.appendChild(j)),e&&h(j,e),f&&n(j,f),j}function j(a,c){a.appendChild(b.createTextNode(c))}function k(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function l(a){a.parentNode.removeChild(a)}function m(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function n(a,b){a.setAttribute("class",m(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function o(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",m(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function p(a){a.setAttribute("class","")}var q="http://www.w3.org/2000/svg",r="http://www.w3.org/2000/xmlns/";return{_node:i(this,a,d,e,f,g?g._node:void 0),_parent:g,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return k(this._node),this},remove:function(){return l(this._node),this},elem:function(a,b,d,e){return c.svg(a,b,d,e,this)},text:function(a){return j(this._node,a),this},addClass:function(a){return n(this._node,a),this},removeClass:function(a){return o(this._node,a),this},removeAllClasses:function(){return p(this._node),this},classes:function(){return m(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);n=c.createSvg(p,a.width,a.height,a.classNames.chart),f=c.getBounds(n,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(n,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,c.getHeight)),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(n,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,c.getWidth));var i=c.createChartRect(n,a,b,e),j=n.elem("g"),k=n.elem("g");c.createXAxis(i,d,k,j,a),c.createYAxis(i,f,k,j,e,a);for(var l=0;l4)for(var t=c.catmullRom2bezier(q),u=0;ua.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);o=c.createSvg(q,a.width,a.height,a.classNames.chart),b=c.createChartRect(o,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=0;m=n-j?"0":"1",t=["M",r.x,r.y,"A",e,e,0,s,0,p.x,p.y];a.donut===!1&&t.push("L",l.x,l.y);var u=i[m].elem("path",{d:t.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(u.attr({value:k[m]},c.xmlNs.uri),a.donut===!0&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),a.showLabel){var v=c.polarToCartesian(l.x,l.y,f,j+(n-j)/2),w=a.labelInterpolationFnc(d.labels?d.labels[m]:k[m],m);i[m].elem("text",{dx:v.x,dy:v.y,"text-anchor":g(l,v,a.labelDirection)},a.classNames.label).text(""+w)}j=n}}function i(){h(n.currentOptions)}function j(){a.removeEventListener("resize",i),n.clear()}function k(a){n.addOptionsListener(a)}function l(a){n.removeOptionsListener(a)}function m(){h(n.currentOptions)}var n,o,p={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},q=c.querySelector(b);q.chartist&&q.chartist.detach(),n=c.optionsProvider(p,e,f),h(n.currentOptions),a.addEventListener("resize",m);var r={version:c.version,update:i,detach:j,addOptionsListener:k,removeOptionsListener:l};return q.chartist=r,r}}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 75a69083..36366658 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getHeight","svgElement","clientHeight","Math","round","getBBox","height","parentNode","getWidth","clientWidth","width","querySelector","query","Node","createSvg","container","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","empty","appendChild","_node","getDataArray","data","array","i","series","length","normalizeDataArray","dataArray","j","orderOfMagnitude","value","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","forEach","index","interpolatedValue","pos","showGrid","classNames","horizontal","join","showLabel","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCrrentOptions","currentOptions","baseOptions","mql","matchMedia","matches","clearMediaQueryListeners","mediaQueryListeners","removeListener","optionsListeners","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":22840,"pos":22826,"col":12,"line":573,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":22840,"pos":22826,"col":12,"line":573,"value":"currentOptions","type":"name"},"name":"currentOptions"},"addOptionsListener","callback","removeOptionsListener","splice","indexOf","clear","catmullRom2bezier","crp","z","d","iLen","p","xmlNs","qualifiedName","prefix","uri","name","attributes","insertFirst","parent","node","ns","Object","keys","key","setAttributeNS","setAttribute","createElementNS","svgNs","firstChild","insertBefore","t","createTextNode","removeChild","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","_parent","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","svgPathString","lineSmooth","cr","k","l","line","update","detach","removeEventListener","updateChart","chartist","addEventListener","api","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","endAngle","start","end","arcSweep","path","slice","style","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.1.14\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.1.14';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n //TODO: move into Chartist.svg\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its height\n * @return {Number} The elements height in pixels\n */\n Chartist.getHeight = function (svgElement) {\n return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight;\n };\n\n //TODO: move into Chartist.svg\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its width\n * @return {Number} The elements width in pixels\n */\n Chartist.getWidth = function (svgElement) {\n return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width || '100%',\n height: height || '100%'\n }).removeAllClasses().addClass(className);\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = Chartist.svg('svg').attr({\n width: width || '100%',\n height: height || '100%'\n }).addClass(className);\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, offsetFnc(label._node));\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (options.height || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset,\n x2: (options.width || Chartist.getWidth(svg._node)) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n pos = chartRect.x1 + chartRect.width() / data.labels.length * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var label = labels.elem('text', {\n dx: pos + 2\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n label.attr({\n dy: chartRect.y1 + Chartist.getHeight(label._node) + options.axisX.offset\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n pos = chartRect.y1 - chartRect.height() / bounds.values.length * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n }\n\n if (options.axisY.showLabel) {\n labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\n * @param {Object} options Options set by user\n * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart\n * @param {Function} optionsChangedCallbackFnc The callback that will be executed when a media change triggered new options to be used. The callback function will receive the new options as first parameter.\n * @return {Object} The consolidated options object from the defaults, base and matching responsive options\n */\n Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n optionsListeners = [],\n i;\n\n function updateCrrentOptions() {\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\n function clearMediaQueryListeners() {\n mediaQueryListeners.forEach(function(mql) {\n mql.removeListener(updateCrrentOptions);\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(updateCrrentOptions);\n mediaQueryListeners.push(mql);\n }\n }\n // Execute initially so we get the correct current options\n updateCrrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n addOptionsListener: function(callback) {\n optionsListeners.push(callback);\n },\n removeOptionsListener: function(callback) {\n optionsListeners.splice(optionsListeners.indexOf(callback), 1);\n },\n clear: function() {\n optionsListeners = [];\n clearMediaQueryListeners();\n }\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\n\n Chartist.svg = function(name, attributes, className, insertFirst, parent) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/';\n\n function attr(node, attributes, ns) {\n Object.keys(attributes).forEach(function(key) {\n if(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\n }\n\n function elem(svg, name, attributes, className, insertFirst, parentNode) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return node;\n }\n\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\n }\n\n function remove(node) {\n node.parentNode.removeChild(node);\n }\n\n function classes(node) {\n return node.getAttribute('class') ? node.getAttribute('class').trim().split(/\\s+/) : [];\n }\n\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\n }\n\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n return {\n _node: elem(this, name, attributes, className, insertFirst, parent ? parent._node : undefined),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.svg(name, attributes, className, insertFirst, this);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns an object handle to the internal closure. Currently you can use the returned object only for updating / redrawing the 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 with a version and an update method to manually redraw the chart\n *\n * @example\n * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n }\n }\n\n if (options.showLine) {\n var svgPathString = 'M' + pathCoordinates[0] + ',' + pathCoordinates[1] + ' ';\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n svgPathString += 'C' + cr[k].join();\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n svgPathString += 'L ' + pathCoordinates[l - 1] + ',' + pathCoordinates[l];\n }\n }\n\n seriesGroups[i].elem('path', {\n d: svgPathString\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Line\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Line\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Line\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 function updateChart() {\n createChart(optionsProvider.currentOptions);\n }\n\n window.addEventListener('resize', updateChart);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\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 * This method creates a new bar chart and returns an object handle with delegations to the internal closure of the bar chart. You can use the returned object to redraw the chart.\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 with a version and an update method to manually redraw the chart\n *\n * @example\n * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with SASS and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Bar\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Bar\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Bar\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 window.addEventListener('resize', update);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // If we need to show labels we need to add the label for this slice now\n if(options.showLabel) {\n // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n seriesGroups[i].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\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Pie\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Pie\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 function updateChart() {\n createChart(optionsProvider.currentOptions);\n }\n\n window.addEventListener('resize', updateChart);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getHeight","svgElement","clientHeight","Math","round","getBBox","height","parentNode","getWidth","clientWidth","width","querySelector","query","Node","createSvg","container","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","empty","appendChild","_node","getDataArray","data","array","i","series","length","normalizeDataArray","dataArray","j","orderOfMagnitude","value","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","forEach","index","interpolatedValue","pos","showGrid","classNames","horizontal","join","showLabel","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCrrentOptions","currentOptions","baseOptions","mql","matchMedia","matches","clearMediaQueryListeners","mediaQueryListeners","removeListener","optionsListeners","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":22840,"pos":22826,"col":12,"line":573,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":22840,"pos":22826,"col":12,"line":573,"value":"currentOptions","type":"name"},"name":"currentOptions"},"addOptionsListener","callback","removeOptionsListener","splice","indexOf","clear","catmullRom2bezier","crp","z","d","iLen","p","xmlNs","qualifiedName","prefix","uri","name","attributes","insertFirst","parent","node","ns","Object","keys","key","setAttributeNS","setAttribute","createElementNS","svgNs","firstChild","insertBefore","t","createTextNode","removeChild","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","_parent","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaPathElements","slice","areaBaseProjected","areaBase","area","line","update","detach","removeEventListener","updateChart","chartist","addEventListener","api","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","endAngle","start","end","arcSweep","path","style","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.1.15\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.1.14';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n //TODO: move into Chartist.svg\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its height\n * @return {Number} The elements height in pixels\n */\n Chartist.getHeight = function (svgElement) {\n return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight;\n };\n\n //TODO: move into Chartist.svg\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its width\n * @return {Number} The elements width in pixels\n */\n Chartist.getWidth = function (svgElement) {\n return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width || '100%',\n height: height || '100%'\n }).removeAllClasses().addClass(className);\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = Chartist.svg('svg').attr({\n width: width || '100%',\n height: height || '100%'\n }).addClass(className);\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, offsetFnc(label._node));\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (options.height || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset,\n x2: (options.width || Chartist.getWidth(svg._node)) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n pos = chartRect.x1 + chartRect.width() / data.labels.length * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var label = labels.elem('text', {\n dx: pos + 2\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n label.attr({\n dy: chartRect.y1 + Chartist.getHeight(label._node) + options.axisX.offset\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n pos = chartRect.y1 - chartRect.height() / bounds.values.length * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n }\n\n if (options.axisY.showLabel) {\n labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\n * @param {Object} options Options set by user\n * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart\n * @param {Function} optionsChangedCallbackFnc The callback that will be executed when a media change triggered new options to be used. The callback function will receive the new options as first parameter.\n * @return {Object} The consolidated options object from the defaults, base and matching responsive options\n */\n Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n optionsListeners = [],\n i;\n\n function updateCrrentOptions() {\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\n function clearMediaQueryListeners() {\n mediaQueryListeners.forEach(function(mql) {\n mql.removeListener(updateCrrentOptions);\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(updateCrrentOptions);\n mediaQueryListeners.push(mql);\n }\n }\n // Execute initially so we get the correct current options\n updateCrrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n addOptionsListener: function(callback) {\n optionsListeners.push(callback);\n },\n removeOptionsListener: function(callback) {\n optionsListeners.splice(optionsListeners.indexOf(callback), 1);\n },\n clear: function() {\n optionsListeners = [];\n clearMediaQueryListeners();\n }\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\n\n Chartist.svg = function(name, attributes, className, insertFirst, parent) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/';\n\n function attr(node, attributes, ns) {\n Object.keys(attributes).forEach(function(key) {\n if(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\n }\n\n function elem(svg, name, attributes, className, insertFirst, parentNode) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return node;\n }\n\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\n }\n\n function remove(node) {\n node.parentNode.removeChild(node);\n }\n\n function classes(node) {\n return node.getAttribute('class') ? node.getAttribute('class').trim().split(/\\s+/) : [];\n }\n\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\n }\n\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n return {\n _node: elem(this, name, attributes, className, insertFirst, parent ? parent._node : undefined),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.svg(name, attributes, className, insertFirst, this);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns an object handle to the internal closure. Currently you can use the returned object only for updating / redrawing the 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 with a version and an update method to manually redraw the chart\n *\n * @example\n * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Line\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Line\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Line\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 function updateChart() {\n createChart(optionsProvider.currentOptions);\n }\n\n window.addEventListener('resize', updateChart);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\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 * This method creates a new bar chart and returns an object handle with delegations to the internal closure of the bar chart. You can use the returned object to redraw the chart.\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 with a version and an update method to manually redraw the chart\n *\n * @example\n * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with SASS and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Bar\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Bar\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Bar\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 window.addEventListener('resize', update);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // If we need to show labels we need to add the label for this slice now\n if(options.showLabel) {\n // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n seriesGroups[i].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\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Pie\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Pie\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 function updateChart() {\n createChart(optionsProvider.currentOptions);\n }\n\n window.addEventListener('resize', updateChart);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/libdist/scss/chartist.scss b/libdist/scss/chartist.scss index a9fb7498..e7b6699a 100644 --- a/libdist/scss/chartist.scss +++ b/libdist/scss/chartist.scss @@ -59,6 +59,11 @@ } } +@mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) { + stroke: none; + fill-opacity: $ct-area-opacity; +} + @mixin ct-chart-bar($ct-bar-width: $ct-bar-width) { fill: none; stroke-width: $ct-bar-width; @@ -74,7 +79,7 @@ stroke: $color; } - .#{$ct-class-slice}:not(.#{$ct-class-donut}) { + .#{$ct-class-slice}:not(.#{$ct-class-donut}), .#{$ct-class-area} { fill: $color; } } @@ -96,6 +101,10 @@ @include ct-chart-line($ct-line-width); } + .#{$ct-class-area} { + @include ct-chart-area(); + } + .#{$ct-class-bar} { @include ct-chart-bar($ct-bar-width); } diff --git a/libdist/scss/settings/_chartist-settings.scss b/libdist/scss/settings/_chartist-settings.scss index b96888da..51f69d1d 100644 --- a/libdist/scss/settings/_chartist-settings.scss +++ b/libdist/scss/settings/_chartist-settings.scss @@ -11,6 +11,7 @@ $ct-class-label: ct-label !default; $ct-class-series: ct-series !default; $ct-class-line: ct-line !default; $ct-class-point: ct-point !default; +$ct-class-area: ct-area !default; $ct-class-bar: ct-bar !default; $ct-class-slice: ct-slice !default; $ct-class-donut: ct-donut !default; @@ -36,6 +37,8 @@ $ct-line-dasharray: false !default; $ct-point-size: 10px !default; // Line chart point, can be either round or square $ct-point-shape: round !default; +// Area fill transparency between 0 and 1 +$ct-area-opacity: 0.1 !default; // Bar chart bar width $ct-bar-width: 10px !default; diff --git a/package.json b/package.json index 6ae4a222..98adb400 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.1.14", + "version": "0.1.15", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From c18990e05f3f7cf6cdd645501be04eb1c69eb332 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 28 Sep 2014 13:00:44 +0200 Subject: [PATCH 006/593] Added latest grunt-sass version and changed sourceMap config --- Gruntfile.js | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 87905598..1bf2ddc2 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -153,7 +153,7 @@ module.exports = function (grunt) { }, dist: { options: { - sourceComments: 'none' + sourceMap: false }, files: [ { @@ -167,7 +167,7 @@ module.exports = function (grunt) { }, server: { options: { - sourceComments: 'map' + sourceMap: true }, files: [ { diff --git a/package.json b/package.json index 98adb400..3691ea43 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "grunt-concurrent": "~0.4.1", "grunt-contrib-clean": "~0.5.0", "grunt-contrib-coffee": "~0.7.0", - "grunt-sass": "~0.12.1", + "grunt-sass": "~0.14.2", "grunt-contrib-concat": "~0.3.0", "grunt-contrib-connect": "~0.5.0", "grunt-contrib-copy": "~0.4.1", From 8b2b284423bce07f62ec77a074be7fb3078f6654 Mon Sep 17 00:00:00 2001 From: Jon Sadka Date: Mon, 29 Sep 2014 16:44:29 -0700 Subject: [PATCH 007/593] Update README.md Removed duplicate word 'is' on line 26 Fixed typo: "problem which is is already solved" --> "problem which is already solved" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45b9a7e2..2dd8c276 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ That's why we have started Chartist.js and our goal is to solve all of the above Chartist's goal is to provide a simple, lightweight and non-intrusive library to responsive craft charts on your website. It's important to understand that one of the main intentions of Chartist.js is to rely on standards rather than providing -a own solution to the problem which is is already solved by the standard. We need to leverage the power of the browsers +a own solution to the problem which is already solved by the standard. We need to leverage the power of the browsers today and say good bye to the idea of solving all problems ourselves. Chartist works with inline-SVG and therefore leverages the power of the DOM to provide parts of its functionality. This From ffbd900cca5e93cb00804155085a68c8928dd0a5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 4 Oct 2014 21:54:20 +0200 Subject: [PATCH 008/593] Added basic event handling module --- Gruntfile.js | 3 +- source/scripts/chartist.event.js | 71 ++++++++++++++++++++++++++++++++ source/site/layouts/default.hbs | 1 + 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 source/scripts/chartist.event.js diff --git a/Gruntfile.js b/Gruntfile.js index 1bf2ddc2..6c60cb73 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -341,6 +341,7 @@ module.exports = function (grunt) { dist: { src: [ 'source/scripts/chartist.core.js', + 'source/scripts/chartist.event.js', 'source/scripts/chartist.svg.js', 'source/scripts/chartist.line.js', 'source/scripts/chartist.bar.js', @@ -389,7 +390,7 @@ module.exports = function (grunt) { banner: pkg.config.banner }, files: { - 'libdist/chartist.js': ['source/scripts/chartist.core.js', 'source/scripts/chartist.svg.js', 'source/scripts/chartist.line.js', 'source/scripts/chartist.bar.js', 'source/scripts/chartist.pie.js'] + 'libdist/chartist.js': ['source/scripts/chartist.core.js', 'source/scripts/chartist.event.js', 'source/scripts/chartist.svg.js', 'source/scripts/chartist.line.js', 'source/scripts/chartist.bar.js', 'source/scripts/chartist.pie.js'] } } }, diff --git a/source/scripts/chartist.event.js b/source/scripts/chartist.event.js new file mode 100644 index 00000000..dd8464e7 --- /dev/null +++ b/source/scripts/chartist.event.js @@ -0,0 +1,71 @@ +/** + * A very basic event module that helps to generate and catch events. + * + * @module Chartist.Event + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + Chartist.EventEmitter = function () { + var handlers = []; + + /** + * Add an event handler for a specific event + * + * @memberof Chartist.Event + * @param {String} event The event name + * @param {Function} handler A event handler function + */ + function addEventHandler(event, handler) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + } + + /** + * Remove an event handler of a specific event name or remove all event handlers for a specific event. + * + * @memberof Chartist.Event + * @param {String} event The event name where a specific or all handlers should be removed + * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. + */ + function removeEventHandler(event, handler) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + // If handler is set we will look for a specific handler and only remove this + if(handler) { + handlers[event].splice(handlers[event].indexOf(handler), 1); + if(handlers[event].length === 0) { + delete handlers[event]; + } + } else { + // If no handler is specified we remove all handlers for this event + delete handlers[event]; + } + } + } + + /** + * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. + * + * @memberof Chartist.Event + * @param {String} event The event name that should be triggered + * @param {*} data Arbitrary data that will be passed to the event handler callback functions + */ + function emit(event, data) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + handlers[event].forEach(function(handler) { + handler(data); + }); + } + } + + return { + addEventHandler: addEventHandler, + removeEventHandler: removeEventHandler, + emit: emit + }; + }; + +}(window, document, Chartist)); \ No newline at end of file diff --git a/source/site/layouts/default.hbs b/source/site/layouts/default.hbs index 8dcf5057..82b24a34 100644 --- a/source/site/layouts/default.hbs +++ b/source/site/layouts/default.hbs @@ -64,6 +64,7 @@ + From 0fcb94d25b6f7d56628799aa1352f1e6d39ce18d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 4 Oct 2014 22:05:55 +0200 Subject: [PATCH 009/593] Refactored Svg Module, added new methods and documentation --- source/scripts/chartist.core.js | 14 +-- source/scripts/chartist.svg.js | 174 ++++++++++++++++++++++++++++++-- test/spec/spec-svg.js | 20 ++-- 3 files changed, 184 insertions(+), 24 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 55aa6380..f8eb60db 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -52,7 +52,7 @@ Chartist.version = '0.1.14'; return target; }; - //TODO: move into Chartist.svg + //TODO: move into Chartist.Svg /** * Get element height with fallback to svg BoundingBox or parent container dimensions: * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) @@ -65,7 +65,7 @@ Chartist.version = '0.1.14'; return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight; }; - //TODO: move into Chartist.svg + //TODO: move into Chartist.Svg /** * Get element width with fallback to svg BoundingBox or parent container dimensions: * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) @@ -113,7 +113,7 @@ Chartist.version = '0.1.14'; } else { // Create svg object with width and height or use 100% as default - svg = Chartist.svg('svg').attr({ + svg = Chartist.Svg('svg').attr({ width: width || '100%', height: height || '100%' }).addClass(className); @@ -406,8 +406,8 @@ Chartist.version = '0.1.14'; * @memberof Chartist.Core * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element * @param {Object} data The Object that contains the data to be visualized in the chart - * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Object} options The Object that contains all the optional values for the chart */ Chartist.createXAxis = function (chartRect, data, grid, labels, options) { @@ -450,8 +450,8 @@ Chartist.version = '0.1.14'; * @memberof Chartist.Core * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Number} offset Offset for the y-axis * @param {Object} options The Object that contains all the optional values for the chart */ diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index df26dfdc..17f9ee76 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -1,7 +1,7 @@ /** * Chartist SVG module for simple SVG DOM abstraction * - * @module Chartist.svg + * @module Chartist.Svg */ /* global Chartist */ (function(window, document, Chartist) { @@ -13,13 +13,38 @@ uri: 'http://gionkunz.github.com/chartist-js/ct' }; - Chartist.svg = function(name, attributes, className, insertFirst, parent) { + /** + * 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. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element to create + * @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. + * @param {String} className This class or class list will be added to the SVG element + * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child + * @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 + * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + Chartist.Svg = function(name, attributes, className, parent, insertFirst) { var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/'; + xmlNs = 'http://www.w3.org/2000/xmlns/', + xhtmlNs = 'http://www.w3.org/1999/xhtml'; + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Chartist.Svg + * @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. + * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @returns {Object} The current wrapper object will be returned so it can be used for chaining. + */ function attr(node, attributes, ns) { Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; + } + if(ns) { node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); } else { @@ -30,7 +55,17 @@ return node; } - function elem(svg, name, attributes, className, insertFirst, parentNode) { + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + function elem(name, attributes, className, parentNode, insertFirst) { var node = document.createElementNS(svgNs, name); // If this is an SVG element created then custom namespace @@ -57,24 +92,123 @@ return node; } + /** + * 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. + * + * @memberof Chartist.Svg + * @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 + * @param {String} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox + * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox + * @param {String} [width] The width of the foreignElement + * @param {String} [height] The height of the foreignElement + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @returns {Object} New wrapper object that wraps the foreignObject element + */ + function foreignObject(content, x, y, width, height, className, parent, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; + } + + // Adding namespace to content element + content.setAttribute('xmlns', xhtmlNs); + + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = Chartist.Svg('foreignObject', { + x: x, + y: y, + width: width, + height: height + }, className, parent, insertFirst); + + // Add content to foreignObjectElement + fnObj._node.appendChild(content); + + return fnObj; + } + + /** + * This method adds a new text element to the current Chartist.Svg wrapper. + * + * @memberof Chartist.Svg + * @param {String} t The text that should be added to the text element that is created + * @returns {Object} The same wrapper object that was used to add the newly created element + */ function text(node, t) { node.appendChild(document.createTextNode(t)); } + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Chartist.Svg + * @returns {Object} The same wrapper object that got emptied + */ function empty(node) { while (node.firstChild) { node.removeChild(node.firstChild); } } + /** + * 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. + * + * @memberof Chartist.Svg + * @returns {Object} The parent wrapper object of the element that got removed + */ function remove(node) { node.parentNode.removeChild(node); } + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Chartist.Svg + * @param {Object} newElement The new wrapper object that will be used to replace the current wrapper object + * @returns {Object} The wrapper of the new element + */ + function replace(node, newChild) { + node.parentNode.replaceChild(newChild, node); + } + + /** + * This method will append an element to the current element as a child. + * + * @memberof Chartist.Svg + * @param {Object} element The element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @returns {Object} The wrapper of the appended object + */ + function append(node, child, insertFirst) { + if(insertFirst && node.firstChild) { + node.insertBefore(child, node.firstChild); + } else { + node.appendChild(child); + } + } + + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Chartist.Svg + * @returns {Array} A list of classes or an empty array if there are no classes on the current element + */ function classes(node) { return node.getAttribute('class') ? node.getAttribute('class').trim().split(/\s+/) : []; } + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ function addClass(node, names) { node.setAttribute('class', classes(node) @@ -85,6 +219,13 @@ ); } + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ function removeClass(node, names) { var removedClasses = names.trim().split(/\s+/); @@ -93,12 +234,18 @@ }).join(' ')); } + /** + * Removes all classes from the current element. + * + * @memberof Chartist.Svg + * @returns {Object} The wrapper of the current element + */ function removeAllClasses(node) { node.setAttribute('class', ''); } return { - _node: elem(this, name, attributes, className, insertFirst, parent ? parent._node : undefined), + _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), _parent: parent, parent: function() { return this._parent; @@ -113,10 +260,23 @@ }, remove: function() { remove(this._node); - return this; + return this.parent(); + }, + replace: function(newElement) { + newElement._parent = this._parent; + replace(this._node, newElement._node); + return newElement; + }, + append: function(element, insertFirst) { + element._parent = this; + append(this._node, element._node, insertFirst); + return element; }, elem: function(name, attributes, className, insertFirst) { - return Chartist.svg(name, attributes, className, insertFirst, this); + return Chartist.Svg(name, attributes, className, this, insertFirst); + }, + foreignObject: function(content, x, y, width, height, className, insertFirst) { + return foreignObject(content, x, y, width, height, className, this, insertFirst); }, text: function(t) { text(this._node, t); diff --git a/test/spec/spec-svg.js b/test/spec/spec-svg.js index ee28ae7a..09959834 100644 --- a/test/spec/spec-svg.js +++ b/test/spec/spec-svg.js @@ -11,11 +11,11 @@ describe('Chartist SVG', function () { }); it('should exist in global namespace', function () { - expect(window.Chartist.svg).toBeDefined(); + expect(window.Chartist.Svg).toBeDefined(); }); it('should create a valid svg dom element', function () { - var svg = window.Chartist.svg('svg'); + var svg = window.Chartist.Svg('svg'); expect(svg).toBeDefined(); expect(svg._node).toBeDefined(); @@ -23,7 +23,7 @@ describe('Chartist SVG', function () { }); it('should create a valid svg dom element with attributes', function () { - var svg = window.Chartist.svg('svg', { + var svg = window.Chartist.Svg('svg', { width: '100%', height: '100%' }); @@ -36,7 +36,7 @@ describe('Chartist SVG', function () { }); it('should create nested objects with attributes', function () { - var svg = window.Chartist.svg('svg'); + var svg = window.Chartist.Svg('svg'); svg.elem('g').elem('g').elem('circle', { cx: 100, cy: 100, @@ -51,7 +51,7 @@ describe('Chartist SVG', function () { }); it('should allow to set attributes manually', function () { - var svg = window.Chartist.svg('svg'); + var svg = window.Chartist.Svg('svg'); svg.elem('circle').attr({ cx: 100, cy: 100, @@ -66,7 +66,7 @@ describe('Chartist SVG', function () { }); it('should clear on each nesting level', function () { - var svg = window.Chartist.svg('svg'); + var svg = window.Chartist.Svg('svg'); var group = svg.elem('g'); group.elem('circle'); group.elem('circle'); @@ -83,7 +83,7 @@ describe('Chartist SVG', function () { }); it('should allow to remove a certain element', function () { - var svg = window.Chartist.svg('svg'); + var svg = window.Chartist.Svg('svg'); var text = svg.elem('text'); expect(svg._node).toBeDefined(); @@ -95,7 +95,7 @@ describe('Chartist SVG', function () { }); it('should allow to write text content into elements', function () { - var svg = window.Chartist.svg('svg'); + var svg = window.Chartist.Svg('svg'); svg.elem('text').text('Hello World'); expect(svg._node).toBeDefined(); @@ -106,7 +106,7 @@ describe('Chartist SVG', function () { }); it('should allow to add and remove classes on elements', function () { - var svg = window.Chartist.svg('svg') + var svg = window.Chartist.Svg('svg') .addClass('test-class-1') .addClass('test-class-2') // Should not allow duplicates @@ -130,7 +130,7 @@ describe('Chartist SVG', function () { }); it('should allow to travers up in the fluent API chain and set attributes on the way', function () { - var svg = window.Chartist.svg('svg'); + var svg = window.Chartist.Svg('svg'); svg.elem('g').elem('g').elem('g').elem('circle') .parent().attr({ transform: 'rotate(10 10 10)' From 0695950a7a8a599d8656e455c64d86b5daaa4545 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 4 Oct 2014 22:07:22 +0200 Subject: [PATCH 010/593] Enabled live chart script eval to contain var chart = Chartist... --- source/scripts/site/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/scripts/site/main.js b/source/scripts/site/main.js index 88b87167..542a6ae3 100644 --- a/source/scripts/site/main.js +++ b/source/scripts/site/main.js @@ -5,9 +5,9 @@ window.hljs.initHighlightingOnLoad(); function evalChartistCode(code, chartElement) { // Modify the code to use a proper selector using the ID of the example as well as return the Chartist object - var modified = code.replace(/Chartist\s*\.\s*(.+)\(\s*['"](.+)['"]/, function(match, type) { - return ['var chartist = Chartist.', type, '(chartElement'].join(''); - }) + '; return chartist;'; + var modified = code.replace(/.*Chartist\s*\.\s*(.+)\(\s*['"](.+)['"]/, function(match, type) { + return ['var chart = Chartist.', type, '(chartElement'].join(''); + }) + '; return chart;'; // Remove any declaration of $chart as we are passing $chart to our function eval modified = modified.replace(/var \$chart.+;/, ''); From e0617921e35a24574303d0106ba36c28d1d4ee5d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 4 Oct 2014 22:07:53 +0200 Subject: [PATCH 011/593] Also enabled params and return documentation for functions --- source/site/partials/dox/dox-member.hbs | 49 ++++++++++++------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/source/site/partials/dox/dox-member.hbs b/source/site/partials/dox/dox-member.hbs index 546d7b34..2836f45f 100644 --- a/source/site/partials/dox/dox-member.hbs +++ b/source/site/partials/dox/dox-member.hbs @@ -9,34 +9,31 @@
{{{description.summary}}}
- {{#is ctx.type 'method'}} - {{#if (doxTagsOfType this 'param')}} -
Parameters
- {{#each (doxTagsOfType this 'param')}} -
- {{name}} - ({{#each types}} - {{this}} - {{/each}}) -
{{description}}
-
- {{/each}} - {{/if}} - - {{#if (doxTagsOfType this 'return')}} - {{#with (doxTag this 'return')}} -
Returns
+ {{#if (doxTagsOfType this 'param')}} +
Parameters
+ {{#each (doxTagsOfType this 'param')}} +
+ {{name}} + ({{#each types}} + {{this}} + {{/each}}) +
{{description}}
+
+ {{/each}} + {{/if}} -
- ({{#each types}} - {{this}} - {{/each}}) -
{{description}}
-
- {{/with}} - {{/if}} + {{#if (doxTagsOfType this 'return')}} + {{#with (doxTag this 'return')}} +
Returns
- {{/is}} +
+ ({{#each types}} + {{this}} + {{/each}}) +
{{description}}
+
+ {{/with}} + {{/if}} {{#if (doxTagsOfType this 'example')}}
Examples
From 71b86b34ddcca6c2fd86eeb13c7edd74cb007a28 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 4 Oct 2014 22:14:25 +0200 Subject: [PATCH 012/593] Major refactoring to include event module --- source/scripts/chartist.bar.js | 82 ++++++++++++--------- source/scripts/chartist.core.js | 123 ++++++++++++++++++++++++-------- source/scripts/chartist.line.js | 84 ++++++++++++---------- source/scripts/chartist.pie.js | 88 ++++++++++++++--------- 4 files changed, 243 insertions(+), 134 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 7ebc9aea..31e1037f 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -8,14 +8,14 @@ 'use strict'; /** - * This method creates a new bar chart and returns an object handle with delegations to the internal closure of the bar chart. You can use the returned object to redraw the chart. + * This method creates a new bar chart and returns API object that you can use for later changes. * * @memberof Chartist.Bar * @param {String|Node} query A selector query string or directly a DOM element * @param {Object} data The data object that needs to consist of a labels and a series array * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object with a version and an update method to manually redraw the chart + * @return {Object} An object which exposes the API for the created chart * * @example * // These are the default options of the line chart @@ -141,7 +141,8 @@ }, optionsProvider, container = Chartist.querySelector(query), - svg; + svg, + eventEmitter = Chartist.EventEmitter(); function createChart(options) { var xAxisOffset, @@ -185,8 +186,8 @@ // Projected 0 point zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - Chartist.createXAxis(chartRect, data, grid, labels, options); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options); + Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); // Draw the series // initialize series groups @@ -227,22 +228,39 @@ }, options.classNames.bar).attr({ 'value': normalizedData[i][j] }, Chartist.xmlNs.uri); + + eventEmitter.emit('draw', { + type: 'bar', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: bar, + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }); } } } + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container /** * Updates the chart which currently does a full reconstruction of the SVG DOM * * @memberof Chartist.Bar - * */ function update() { createChart(optionsProvider.currentOptions); } /** - * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts. + * 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. * * @memberof Chartist.Bar */ @@ -252,54 +270,50 @@ } /** - * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options. + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * * @memberof Chartist.Bar - * @param {Function} callback Callback function that will have the new options as first parameter + * @param {String} event Name of the event. Check the examples for supported events. + * @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. */ - function addOptionsListener(callback) { - optionsProvider.addOptionsListener(callback); + function on(event, handler) { + eventEmitter.addEventHandler(event, handler); } /** - * Remove a responsive options listener that was previously added using the addOptionsListener method. + * 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. * * @memberof Chartist.Bar - * @param {Function} callback The callback function that was registered earlier with addOptionsListener + * @param {String} event Name of the event for which a handler should be removed + * @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. */ - function removeOptionsListener(callback) { - optionsProvider.removeOptionsListener(callback); + function off(event, handler) { + eventEmitter.removeEventHandler(event, handler); } - // If this container already contains chartist, let's try to detach first and unregister all event listeners - if(container.chartist) { - container.chartist.detach(); - } + // Initialization of the chart + + window.addEventListener('resize', update); // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions); - createChart(optionsProvider.currentOptions); - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - window.addEventListener('resize', update); + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { + createChart(optionsProvider.currentOptions); + }, 0); - // Public members + // Public members of the module (revealing module pattern style) var api = { version: Chartist.version, update: update, - detach: detach, - addOptionsListener: addOptionsListener, - removeOptionsListener: removeOptionsListener + on: on, + off: off, + detach: detach }; container.chartist = api; - return api; }; diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index f8eb60db..20afd1b8 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -410,11 +410,12 @@ Chartist.version = '0.1.14'; * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Object} options The Object that contains all the optional values for the chart */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options) { + Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) { // Create X-Axis data.labels.forEach(function (value, index) { var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - pos = chartRect.x1 + chartRect.width() / data.labels.length * index; + space = chartRect.width() / data.labels.length, + pos = chartRect.x1 + space * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -422,23 +423,54 @@ Chartist.version = '0.1.14'; } if (options.axisX.showGrid) { - grid.elem('line', { + var gridElement = grid.elem('line', { x1: pos, y1: chartRect.y1, x2: pos, y2: chartRect.y2 }, [options.classNames.grid, options.classNames.horizontal].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'x', + index: index, + group: grid, + element: gridElement, + x1: pos, + y1: chartRect.y1, + x2: pos, + y2: chartRect.y2 + }); } if (options.axisX.showLabel) { // Use config offset for setting labels of - var label = labels.elem('text', { - dx: pos + 2 + var labelPos = { + x: pos + 2, + y: 0 + }; + + var labelElement = labels.elem('text', { + dx: labelPos.x }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue); // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos - label.attr({ - dy: chartRect.y1 + Chartist.getHeight(label._node) + options.axisX.offset + labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset; + labelElement.attr({ + dy: labelPos.y + }); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'x', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPos.x, + y: labelPos.y, + space: space }); } }); @@ -455,11 +487,12 @@ Chartist.version = '0.1.14'; * @param {Number} offset Offset for the y-axis * @param {Object} options The Object that contains all the optional values for the chart */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options) { + Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) { // Create Y-Axis bounds.values.forEach(function (value, index) { var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - pos = chartRect.y1 - chartRect.height() / bounds.values.length * index; + space = chartRect.height() / bounds.values.length, + pos = chartRect.y1 - space * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -467,20 +500,52 @@ Chartist.version = '0.1.14'; } if (options.axisY.showGrid) { - grid.elem('line', { + var gridElement = grid.elem('line', { x1: chartRect.x1, y1: pos, x2: chartRect.x2, y2: pos }, [options.classNames.grid, options.classNames.vertical].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'y', + index: index, + group: grid, + element: gridElement, + x1: chartRect.x1, + y1: pos, + x2: chartRect.x2, + y2: pos + }); } if (options.axisY.showLabel) { - labels.elem('text', { + // Use calculated offset and include padding for label x position + // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier + var labelPos = { + x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, + y: pos - 2 + }; + + var labelElement = labels.elem('text', { dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, dy: pos - 2, 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start' }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'y', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPos.x, + y: labelPos.y, + space: space + }); } }); }; @@ -510,17 +575,17 @@ Chartist.version = '0.1.14'; * @param {Object} defaultOptions Default options from Chartist * @param {Object} options Options set by user * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart - * @param {Function} optionsChangedCallbackFnc The callback that will be executed when a media change triggered new options to be used. The callback function will receive the new options as first parameter. + * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events * @return {Object} The consolidated options object from the defaults, base and matching responsive options */ - Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions) { + Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions, eventEmitter) { var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options), currentOptions, mediaQueryListeners = [], - optionsListeners = [], i; - function updateCrrentOptions() { + function updateCurrentOptions() { + var previousOptions = currentOptions; currentOptions = Chartist.extend({}, baseOptions); if (responsiveOptions) { @@ -531,11 +596,18 @@ Chartist.version = '0.1.14'; } } } + + if(eventEmitter) { + eventEmitter.emit('optionsChanged', { + previousOptions: previousOptions, + currentOptions: currentOptions + }); + } } - function clearMediaQueryListeners() { + function removeMediaQueryListeners() { mediaQueryListeners.forEach(function(mql) { - mql.removeListener(updateCrrentOptions); + mql.removeListener(updateCurrentOptions); }); } @@ -545,27 +617,18 @@ Chartist.version = '0.1.14'; for (i = 0; i < responsiveOptions.length; i++) { var mql = window.matchMedia(responsiveOptions[i][0]); - mql.addListener(updateCrrentOptions); + mql.addListener(updateCurrentOptions); mediaQueryListeners.push(mql); } } - // Execute initially so we get the correct current options - updateCrrentOptions(); + // Execute initially so we get the correct options + updateCurrentOptions(); return { get currentOptions() { return Chartist.extend({}, currentOptions); }, - addOptionsListener: function(callback) { - optionsListeners.push(callback); - }, - removeOptionsListener: function(callback) { - optionsListeners.splice(optionsListeners.indexOf(callback), 1); - }, - clear: function() { - optionsListeners = []; - clearMediaQueryListeners(); - } + removeMediaQueryListeners: removeMediaQueryListeners }; }; diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index e9059d92..09c636cd 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -10,14 +10,14 @@ 'use strict'; /** - * This method creates a new line chart and returns an object handle to the internal closure. Currently you can use the returned object only for updating / redrawing the chart. + * This method creates a new line chart and returns API object that you can use for later changes. * * @memberof Chartist.Line * @param {String|Node} query A selector query string or directly a DOM element * @param {Object} data The data object that needs to consist of a labels and a series array * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object with a version and an update method to manually redraw the chart + * @return {Object} An object which exposes the API for the created chart * * @example * // These are the default options of the line chart @@ -180,7 +180,8 @@ }, optionsProvider, container = Chartist.querySelector(query), - svg; + svg, + eventEmitter = Chartist.EventEmitter(); function createChart(options) { var xAxisOffset, @@ -222,8 +223,8 @@ var labels = svg.elem('g'), grid = svg.elem('g'); - Chartist.createXAxis(chartRect, data, grid, labels, options); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options); + Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); // Draw the series // initialize series groups @@ -262,6 +263,16 @@ }, options.classNames.point).attr({ 'value': normalizedData[i][j] }, Chartist.xmlNs.uri); + + eventEmitter.emit('draw', { + type: 'point', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: point, + x: p.x, + y: p.y + }); } } @@ -312,79 +323,76 @@ } } + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container /** * Updates the chart which currently does a full reconstruction of the SVG DOM * * @memberof Chartist.Line - * */ function update() { createChart(optionsProvider.currentOptions); } /** - * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts. + * 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. * * @memberof Chartist.Line */ function detach() { window.removeEventListener('resize', update); - optionsProvider.clear(); + optionsProvider.removeMediaQueryListeners(); } /** - * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options. + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * * @memberof Chartist.Line - * @param {Function} callback Callback function that will have the new options as first parameter + * @param {String} event Name of the event. Check the examples for supported events. + * @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. */ - function addOptionsListener(callback) { - optionsProvider.addOptionsListener(callback); + function on(event, handler) { + eventEmitter.addEventHandler(event, handler); } /** - * Remove a responsive options listener that was previously added using the addOptionsListener method. + * 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. * * @memberof Chartist.Line - * @param {Function} callback The callback function that was registered earlier with addOptionsListener + * @param {String} event Name of the event for which a handler should be removed + * @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. */ - function removeOptionsListener(callback) { - optionsProvider.removeOptionsListener(callback); + function off(event, handler) { + eventEmitter.removeEventHandler(event, handler); } - // If this container already contains chartist, let's try to detach first and unregister all event listeners - if(container.chartist) { - container.chartist.detach(); - } + // Initialization of the chart + + window.addEventListener('resize', update); // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions); - createChart(optionsProvider.currentOptions); - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - function updateChart() { + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { createChart(optionsProvider.currentOptions); - } + }, 0); - window.addEventListener('resize', updateChart); - - // Public members + // Public members of the module (revealing module pattern style) var api = { version: Chartist.version, update: update, - detach: detach, - addOptionsListener: addOptionsListener, - removeOptionsListener: removeOptionsListener + on: on, + off: off, + detach: detach }; container.chartist = api; - return api; }; diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index 20eb05e7..b36b6291 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -112,7 +112,8 @@ }, optionsProvider, container = Chartist.querySelector(query), - svg; + svg, + eventEmitter = Chartist.EventEmitter(); function determineAnchorPosition(center, label, direction) { var toTheRight = label.x > center.x; @@ -223,17 +224,42 @@ }); } + // Fire off draw event + eventEmitter.emit('draw', { + type: 'slice', + value: dataArray[i], + totalDataSum: totalDataSum, + index: i, + group: seriesGroups[i], + element: path, + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + // If we need to show labels we need to add the label for this slice now if(options.showLabel) { // Position at the labelRadius distance from center and between start and end angle var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i); - seriesGroups[i].elem('text', { + var labelElement = seriesGroups[i].elem('text', { dx: labelPosition.x, dy: labelPosition.y, 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) }, options.classNames.label).text('' + interpolatedValue); + + // Fire off draw event + eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); } // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues @@ -242,6 +268,12 @@ } } + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container /** * Updates the chart which currently does a full reconstruction of the SVG DOM * @@ -263,58 +295,50 @@ } /** - * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options. + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * * @memberof Chartist.Pie - * @param {Function} callback Callback function that will have the new options as first parameter + * @param {String} event Name of the event. Check the examples for supported events. + * @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. */ - function addOptionsListener(callback) { - optionsProvider.addOptionsListener(callback); + function on(event, handler) { + eventEmitter.addEventHandler(event, handler); } /** - * Remove a responsive options listener that was previously added using the addOptionsListener method. + * 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. * * @memberof Chartist.Pie - * @param {Function} callback The callback function that was registered earlier with addOptionsListener + * @param {String} event Name of the event for which a handler should be removed + * @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. */ - function removeOptionsListener(callback) { - optionsProvider.removeOptionsListener(callback); + function off(event, handler) { + eventEmitter.removeEventHandler(event, handler); } - // If this container already contains chartist, let's try to detach first and unregister all event listeners - if(container.chartist) { - container.chartist.detach(); - } + // Initialization of the chart + + window.addEventListener('resize', update); // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions); - createChart(optionsProvider.currentOptions); - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - function updateChart() { + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { createChart(optionsProvider.currentOptions); - } + }, 0); - window.addEventListener('resize', updateChart); - - // Public members + // Public members of the module (revealing module pattern style) var api = { version: Chartist.version, update: update, - detach: detach, - addOptionsListener: addOptionsListener, - removeOptionsListener: removeOptionsListener + on: on, + off: off, + detach: detach }; container.chartist = api; - return api; }; From 118453fb40209bf4525d07db7b0faeedb16ddd2a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 4 Oct 2014 22:18:27 +0200 Subject: [PATCH 013/593] Added live examples for using events to modify the drawing process --- source/site/data/pages/examples.yml | 19 ++++++++++++ .../example-bar-with-circle-modify-drawing.js | 28 +++++++++++++++++ .../examples/example-line-modify-drawing.js | 30 +++++++++++++++++++ source/styles/site/main.scss | 1 + 4 files changed, 78 insertions(+) create mode 100644 source/site/examples/example-bar-with-circle-modify-drawing.js create mode 100644 source/site/examples/example-line-modify-drawing.js diff --git a/source/site/data/pages/examples.yml b/source/site/data/pages/examples.yml index 6c25ac7e..e65b8f7b 100644 --- a/source/site/data/pages/examples.yml +++ b/source/site/data/pages/examples.yml @@ -49,6 +49,17 @@ sections: You can also only draw the area shapes of the line chart. Area shapes will always be constructed around their areaBase (that can be configured in the options) which also allows you to draw nice bi-polar areas. + - type: live-example + data: + title: Using events to replace graphics + level: 4 + id: example-line-modify-drawing + classes: ct-golden-section + intro: > + Chartist has fixed graphical representations that are chosen because of their flexibility and to + provide a high level of separation of the concerns. However, sometimes you probably would like to use + different shapes or even images for your charts. One way to achieve this is by using the draw events and replace + or add custom SVG shapes. - title: Bar chart examples level: 3 items: @@ -71,6 +82,14 @@ sections: This example makes use of label interpolation and the seriesBarDistance property that allows you to make bars overlap over each other. This then can be used to use the avialable space on mobile better. Resize your browser to see the effect of the responsive configuration. + - type: live-example + data: + title: Add peek cricles using the draw events + level: 4 + id: example-bar-with-circle-modify-drawing + classes: ct-golden-section + intro: > + With the help of draw events we are able to add a custom SVG shape to the peek of our bars. - title: Pie chart examples level: 3 items: diff --git a/source/site/examples/example-bar-with-circle-modify-drawing.js b/source/site/examples/example-bar-with-circle-modify-drawing.js new file mode 100644 index 00000000..c3fac2b0 --- /dev/null +++ b/source/site/examples/example-bar-with-circle-modify-drawing.js @@ -0,0 +1,28 @@ +// Create a simple bi-polar bar chart +var chart = Chartist.Bar('.ct-chart', { + labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'], + series: [ + [1, 2, 4, 8, 6, -2, -1, -4, -6, -2] + ] +}, { + high: 10, + low: -10, + axisX: { + labelInterpolationFnc: function(value, index) { + return index % 2 === 0 ? value : null; + } + } +}); + +// Listen for draw events on the bar chart +chart.on('draw', function(data) { + // If this draw event is of type bar we can use the data to create additional content + if(data.type === 'bar') { + // We use the group element of the current series to append a simple circle with the bar peek coordinates and a circle radius that is depending on the value + data.group.append(Chartist.Svg('circle', { + cx: data.x2, + cy: data.y2, + r: Math.abs(data.value) * 2 + 5 + }, 'ct-slice')); + } +}); \ No newline at end of file diff --git a/source/site/examples/example-line-modify-drawing.js b/source/site/examples/example-line-modify-drawing.js new file mode 100644 index 00000000..e61e1ada --- /dev/null +++ b/source/site/examples/example-line-modify-drawing.js @@ -0,0 +1,30 @@ +var chart = Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5], + series: [ + [12, 9, 7, 8, 5] + ] +}); + +// Listening for draw events that get emitted by the Chartist chart +chart.on('draw', function(data) { + // If the draw event was triggered from drawing a point on the line chart + if(data.type === 'point') { + // We are creating a new path SVG element that draws a triangle around the point coordinates + var triangle = Chartist.Svg('path', { + d: ['M', + data.x, + data.y - 15, + 'L', + data.x - 15, + data.y + 8, + 'L', + data.x + 15, + data.y + 8, + 'z'].join(' '), + style: 'fill-opacity: 1' + }, 'ct-area'); + + // With data.element we get the Chartist SVG wrapper and we can replace the original point drawn by Chartist with our newly created triangle + data.element.replace(triangle); + } +}); \ No newline at end of file diff --git a/source/styles/site/main.scss b/source/styles/site/main.scss index eddcbb71..f74a5e26 100644 --- a/source/styles/site/main.scss +++ b/source/styles/site/main.scss @@ -86,6 +86,7 @@ font-weight: 700; text-align: center; pointer-events: none; + z-index: 1; &:after { content: ""; From 3e8cac9cf1501fe596cc5db215062d0d386db14e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 4 Oct 2014 22:23:42 +0200 Subject: [PATCH 014/593] Updated to version 0.2.0 --- bower.json | 2 +- libdist/chartist.js | 637 ++++++++++++++++++++++++++++++--------- libdist/chartist.min.css | 4 +- libdist/chartist.min.js | 4 +- libdist/chartist.min.map | 2 +- package.json | 2 +- 6 files changed, 495 insertions(+), 156 deletions(-) diff --git a/bower.json b/bower.json index f117c6aa..4ceaa764 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.1.15", + "version": "0.2.0", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index 26afd98f..d1dd873c 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.1.15 + /* Chartist.js 0.2.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -69,7 +69,7 @@ return target; }; - //TODO: move into Chartist.svg + //TODO: move into Chartist.Svg /** * Get element height with fallback to svg BoundingBox or parent container dimensions: * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) @@ -82,7 +82,7 @@ return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight; }; - //TODO: move into Chartist.svg + //TODO: move into Chartist.Svg /** * Get element width with fallback to svg BoundingBox or parent container dimensions: * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) @@ -130,7 +130,7 @@ } else { // Create svg object with width and height or use 100% as default - svg = Chartist.svg('svg').attr({ + svg = Chartist.Svg('svg').attr({ width: width || '100%', height: height || '100%' }).addClass(className); @@ -423,15 +423,16 @@ * @memberof Chartist.Core * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element * @param {Object} data The Object that contains the data to be visualized in the chart - * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Object} options The Object that contains all the optional values for the chart */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options) { + Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) { // Create X-Axis data.labels.forEach(function (value, index) { var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - pos = chartRect.x1 + chartRect.width() / data.labels.length * index; + space = chartRect.width() / data.labels.length, + pos = chartRect.x1 + space * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -439,23 +440,54 @@ } if (options.axisX.showGrid) { - grid.elem('line', { + var gridElement = grid.elem('line', { x1: pos, y1: chartRect.y1, x2: pos, y2: chartRect.y2 }, [options.classNames.grid, options.classNames.horizontal].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'x', + index: index, + group: grid, + element: gridElement, + x1: pos, + y1: chartRect.y1, + x2: pos, + y2: chartRect.y2 + }); } if (options.axisX.showLabel) { // Use config offset for setting labels of - var label = labels.elem('text', { - dx: pos + 2 + var labelPos = { + x: pos + 2, + y: 0 + }; + + var labelElement = labels.elem('text', { + dx: labelPos.x }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue); // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos - label.attr({ - dy: chartRect.y1 + Chartist.getHeight(label._node) + options.axisX.offset + labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset; + labelElement.attr({ + dy: labelPos.y + }); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'x', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPos.x, + y: labelPos.y, + space: space }); } }); @@ -467,16 +499,17 @@ * @memberof Chartist.Core * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Number} offset Offset for the y-axis * @param {Object} options The Object that contains all the optional values for the chart */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options) { + Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) { // Create Y-Axis bounds.values.forEach(function (value, index) { var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - pos = chartRect.y1 - chartRect.height() / bounds.values.length * index; + space = chartRect.height() / bounds.values.length, + pos = chartRect.y1 - space * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -484,20 +517,52 @@ } if (options.axisY.showGrid) { - grid.elem('line', { + var gridElement = grid.elem('line', { x1: chartRect.x1, y1: pos, x2: chartRect.x2, y2: pos }, [options.classNames.grid, options.classNames.vertical].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'y', + index: index, + group: grid, + element: gridElement, + x1: chartRect.x1, + y1: pos, + x2: chartRect.x2, + y2: pos + }); } if (options.axisY.showLabel) { - labels.elem('text', { + // Use calculated offset and include padding for label x position + // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier + var labelPos = { + x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, + y: pos - 2 + }; + + var labelElement = labels.elem('text', { dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, dy: pos - 2, 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start' }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'y', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPos.x, + y: labelPos.y, + space: space + }); } }); }; @@ -527,17 +592,17 @@ * @param {Object} defaultOptions Default options from Chartist * @param {Object} options Options set by user * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart - * @param {Function} optionsChangedCallbackFnc The callback that will be executed when a media change triggered new options to be used. The callback function will receive the new options as first parameter. + * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events * @return {Object} The consolidated options object from the defaults, base and matching responsive options */ - Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions) { + Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions, eventEmitter) { var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options), currentOptions, mediaQueryListeners = [], - optionsListeners = [], i; - function updateCrrentOptions() { + function updateCurrentOptions() { + var previousOptions = currentOptions; currentOptions = Chartist.extend({}, baseOptions); if (responsiveOptions) { @@ -548,11 +613,18 @@ } } } + + if(eventEmitter) { + eventEmitter.emit('optionsChanged', { + previousOptions: previousOptions, + currentOptions: currentOptions + }); + } } - function clearMediaQueryListeners() { + function removeMediaQueryListeners() { mediaQueryListeners.forEach(function(mql) { - mql.removeListener(updateCrrentOptions); + mql.removeListener(updateCurrentOptions); }); } @@ -562,27 +634,18 @@ for (i = 0; i < responsiveOptions.length; i++) { var mql = window.matchMedia(responsiveOptions[i][0]); - mql.addListener(updateCrrentOptions); + mql.addListener(updateCurrentOptions); mediaQueryListeners.push(mql); } } - // Execute initially so we get the correct current options - updateCrrentOptions(); + // Execute initially so we get the correct options + updateCurrentOptions(); return { get currentOptions() { return Chartist.extend({}, currentOptions); }, - addOptionsListener: function(callback) { - optionsListeners.push(callback); - }, - removeOptionsListener: function(callback) { - optionsListeners.splice(optionsListeners.indexOf(callback), 1); - }, - clear: function() { - optionsListeners = []; - clearMediaQueryListeners(); - } + removeMediaQueryListeners: removeMediaQueryListeners }; }; @@ -627,10 +690,80 @@ return d; }; + }(window, document, Chartist));;/** + * A very basic event module that helps to generate and catch events. + * + * @module Chartist.Event + */ + /* global Chartist */ + (function (window, document, Chartist) { + 'use strict'; + + Chartist.EventEmitter = function () { + var handlers = []; + + /** + * Add an event handler for a specific event + * + * @memberof Chartist.Event + * @param {String} event The event name + * @param {Function} handler A event handler function + */ + function addEventHandler(event, handler) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + } + + /** + * Remove an event handler of a specific event name or remove all event handlers for a specific event. + * + * @memberof Chartist.Event + * @param {String} event The event name where a specific or all handlers should be removed + * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. + */ + function removeEventHandler(event, handler) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + // If handler is set we will look for a specific handler and only remove this + if(handler) { + handlers[event].splice(handlers[event].indexOf(handler), 1); + if(handlers[event].length === 0) { + delete handlers[event]; + } + } else { + // If no handler is specified we remove all handlers for this event + delete handlers[event]; + } + } + } + + /** + * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. + * + * @memberof Chartist.Event + * @param {String} event The event name that should be triggered + * @param {*} data Arbitrary data that will be passed to the event handler callback functions + */ + function emit(event, data) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + handlers[event].forEach(function(handler) { + handler(data); + }); + } + } + + return { + addEventHandler: addEventHandler, + removeEventHandler: removeEventHandler, + emit: emit + }; + }; + }(window, document, Chartist));;/** * Chartist SVG module for simple SVG DOM abstraction * - * @module Chartist.svg + * @module Chartist.Svg */ /* global Chartist */ (function(window, document, Chartist) { @@ -642,13 +775,38 @@ uri: 'http://gionkunz.github.com/chartist-js/ct' }; - Chartist.svg = function(name, attributes, className, insertFirst, parent) { + /** + * 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. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element to create + * @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. + * @param {String} className This class or class list will be added to the SVG element + * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child + * @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 + * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + Chartist.Svg = function(name, attributes, className, parent, insertFirst) { var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/'; + xmlNs = 'http://www.w3.org/2000/xmlns/', + xhtmlNs = 'http://www.w3.org/1999/xhtml'; + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Chartist.Svg + * @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. + * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @returns {Object} The current wrapper object will be returned so it can be used for chaining. + */ function attr(node, attributes, ns) { Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; + } + if(ns) { node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); } else { @@ -659,7 +817,17 @@ return node; } - function elem(svg, name, attributes, className, insertFirst, parentNode) { + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + function elem(name, attributes, className, parentNode, insertFirst) { var node = document.createElementNS(svgNs, name); // If this is an SVG element created then custom namespace @@ -686,24 +854,123 @@ return node; } + /** + * 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. + * + * @memberof Chartist.Svg + * @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 + * @param {String} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox + * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox + * @param {String} [width] The width of the foreignElement + * @param {String} [height] The height of the foreignElement + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @returns {Object} New wrapper object that wraps the foreignObject element + */ + function foreignObject(content, x, y, width, height, className, parent, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; + } + + // Adding namespace to content element + content.setAttribute('xmlns', xhtmlNs); + + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = Chartist.Svg('foreignObject', { + x: x, + y: y, + width: width, + height: height + }, className, parent, insertFirst); + + // Add content to foreignObjectElement + fnObj._node.appendChild(content); + + return fnObj; + } + + /** + * This method adds a new text element to the current Chartist.Svg wrapper. + * + * @memberof Chartist.Svg + * @param {String} t The text that should be added to the text element that is created + * @returns {Object} The same wrapper object that was used to add the newly created element + */ function text(node, t) { node.appendChild(document.createTextNode(t)); } + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Chartist.Svg + * @returns {Object} The same wrapper object that got emptied + */ function empty(node) { while (node.firstChild) { node.removeChild(node.firstChild); } } + /** + * 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. + * + * @memberof Chartist.Svg + * @returns {Object} The parent wrapper object of the element that got removed + */ function remove(node) { node.parentNode.removeChild(node); } + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Chartist.Svg + * @param {Object} newElement The new wrapper object that will be used to replace the current wrapper object + * @returns {Object} The wrapper of the new element + */ + function replace(node, newChild) { + node.parentNode.replaceChild(newChild, node); + } + + /** + * This method will append an element to the current element as a child. + * + * @memberof Chartist.Svg + * @param {Object} element The element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @returns {Object} The wrapper of the appended object + */ + function append(node, child, insertFirst) { + if(insertFirst && node.firstChild) { + node.insertBefore(child, node.firstChild); + } else { + node.appendChild(child); + } + } + + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Chartist.Svg + * @returns {Array} A list of classes or an empty array if there are no classes on the current element + */ function classes(node) { return node.getAttribute('class') ? node.getAttribute('class').trim().split(/\s+/) : []; } + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ function addClass(node, names) { node.setAttribute('class', classes(node) @@ -714,6 +981,13 @@ ); } + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ function removeClass(node, names) { var removedClasses = names.trim().split(/\s+/); @@ -722,12 +996,18 @@ }).join(' ')); } + /** + * Removes all classes from the current element. + * + * @memberof Chartist.Svg + * @returns {Object} The wrapper of the current element + */ function removeAllClasses(node) { node.setAttribute('class', ''); } return { - _node: elem(this, name, attributes, className, insertFirst, parent ? parent._node : undefined), + _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), _parent: parent, parent: function() { return this._parent; @@ -742,10 +1022,23 @@ }, remove: function() { remove(this._node); - return this; + return this.parent(); + }, + replace: function(newElement) { + newElement._parent = this._parent; + replace(this._node, newElement._node); + return newElement; + }, + append: function(element, insertFirst) { + element._parent = this; + append(this._node, element._node, insertFirst); + return element; }, elem: function(name, attributes, className, insertFirst) { - return Chartist.svg(name, attributes, className, insertFirst, this); + return Chartist.Svg(name, attributes, className, this, insertFirst); + }, + foreignObject: function(content, x, y, width, height, className, insertFirst) { + return foreignObject(content, x, y, width, height, className, this, insertFirst); }, text: function(t) { text(this._node, t); @@ -781,14 +1074,14 @@ 'use strict'; /** - * This method creates a new line chart and returns an object handle to the internal closure. Currently you can use the returned object only for updating / redrawing the chart. + * This method creates a new line chart and returns API object that you can use for later changes. * * @memberof Chartist.Line * @param {String|Node} query A selector query string or directly a DOM element * @param {Object} data The data object that needs to consist of a labels and a series array * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object with a version and an update method to manually redraw the chart + * @return {Object} An object which exposes the API for the created chart * * @example * // These are the default options of the line chart @@ -951,7 +1244,8 @@ }, optionsProvider, container = Chartist.querySelector(query), - svg; + svg, + eventEmitter = Chartist.EventEmitter(); function createChart(options) { var xAxisOffset, @@ -993,8 +1287,8 @@ var labels = svg.elem('g'), grid = svg.elem('g'); - Chartist.createXAxis(chartRect, data, grid, labels, options); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options); + Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); // Draw the series // initialize series groups @@ -1033,6 +1327,16 @@ }, options.classNames.point).attr({ 'value': normalizedData[i][j] }, Chartist.xmlNs.uri); + + eventEmitter.emit('draw', { + type: 'point', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: point, + x: p.x, + y: p.y + }); } } @@ -1083,79 +1387,76 @@ } } + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container /** * Updates the chart which currently does a full reconstruction of the SVG DOM * * @memberof Chartist.Line - * */ function update() { createChart(optionsProvider.currentOptions); } /** - * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts. + * 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. * * @memberof Chartist.Line */ function detach() { window.removeEventListener('resize', update); - optionsProvider.clear(); + optionsProvider.removeMediaQueryListeners(); } /** - * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options. + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * * @memberof Chartist.Line - * @param {Function} callback Callback function that will have the new options as first parameter + * @param {String} event Name of the event. Check the examples for supported events. + * @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. */ - function addOptionsListener(callback) { - optionsProvider.addOptionsListener(callback); + function on(event, handler) { + eventEmitter.addEventHandler(event, handler); } /** - * Remove a responsive options listener that was previously added using the addOptionsListener method. + * 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. * * @memberof Chartist.Line - * @param {Function} callback The callback function that was registered earlier with addOptionsListener + * @param {String} event Name of the event for which a handler should be removed + * @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. */ - function removeOptionsListener(callback) { - optionsProvider.removeOptionsListener(callback); + function off(event, handler) { + eventEmitter.removeEventHandler(event, handler); } - // If this container already contains chartist, let's try to detach first and unregister all event listeners - if(container.chartist) { - container.chartist.detach(); - } + // Initialization of the chart + + window.addEventListener('resize', update); // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions); - createChart(optionsProvider.currentOptions); - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - function updateChart() { + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { createChart(optionsProvider.currentOptions); - } - - window.addEventListener('resize', updateChart); + }, 0); - // Public members + // Public members of the module (revealing module pattern style) var api = { version: Chartist.version, update: update, - detach: detach, - addOptionsListener: addOptionsListener, - removeOptionsListener: removeOptionsListener + on: on, + off: off, + detach: detach }; container.chartist = api; - return api; }; @@ -1170,14 +1471,14 @@ 'use strict'; /** - * This method creates a new bar chart and returns an object handle with delegations to the internal closure of the bar chart. You can use the returned object to redraw the chart. + * This method creates a new bar chart and returns API object that you can use for later changes. * * @memberof Chartist.Bar * @param {String|Node} query A selector query string or directly a DOM element * @param {Object} data The data object that needs to consist of a labels and a series array * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object with a version and an update method to manually redraw the chart + * @return {Object} An object which exposes the API for the created chart * * @example * // These are the default options of the line chart @@ -1303,7 +1604,8 @@ }, optionsProvider, container = Chartist.querySelector(query), - svg; + svg, + eventEmitter = Chartist.EventEmitter(); function createChart(options) { var xAxisOffset, @@ -1347,8 +1649,8 @@ // Projected 0 point zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - Chartist.createXAxis(chartRect, data, grid, labels, options); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options); + Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); // Draw the series // initialize series groups @@ -1389,22 +1691,39 @@ }, options.classNames.bar).attr({ 'value': normalizedData[i][j] }, Chartist.xmlNs.uri); + + eventEmitter.emit('draw', { + type: 'bar', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: bar, + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }); } } } + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container /** * Updates the chart which currently does a full reconstruction of the SVG DOM * * @memberof Chartist.Bar - * */ function update() { createChart(optionsProvider.currentOptions); } /** - * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts. + * 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. * * @memberof Chartist.Bar */ @@ -1414,54 +1733,50 @@ } /** - * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options. + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * * @memberof Chartist.Bar - * @param {Function} callback Callback function that will have the new options as first parameter + * @param {String} event Name of the event. Check the examples for supported events. + * @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. */ - function addOptionsListener(callback) { - optionsProvider.addOptionsListener(callback); + function on(event, handler) { + eventEmitter.addEventHandler(event, handler); } /** - * Remove a responsive options listener that was previously added using the addOptionsListener method. + * 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. * * @memberof Chartist.Bar - * @param {Function} callback The callback function that was registered earlier with addOptionsListener + * @param {String} event Name of the event for which a handler should be removed + * @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. */ - function removeOptionsListener(callback) { - optionsProvider.removeOptionsListener(callback); + function off(event, handler) { + eventEmitter.removeEventHandler(event, handler); } - // If this container already contains chartist, let's try to detach first and unregister all event listeners - if(container.chartist) { - container.chartist.detach(); - } + // Initialization of the chart + + window.addEventListener('resize', update); // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions); - createChart(optionsProvider.currentOptions); - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - window.addEventListener('resize', update); + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { + createChart(optionsProvider.currentOptions); + }, 0); - // Public members + // Public members of the module (revealing module pattern style) var api = { version: Chartist.version, update: update, - detach: detach, - addOptionsListener: addOptionsListener, - removeOptionsListener: removeOptionsListener + on: on, + off: off, + detach: detach }; container.chartist = api; - return api; }; @@ -1580,7 +1895,8 @@ }, optionsProvider, container = Chartist.querySelector(query), - svg; + svg, + eventEmitter = Chartist.EventEmitter(); function determineAnchorPosition(center, label, direction) { var toTheRight = label.x > center.x; @@ -1691,17 +2007,42 @@ }); } + // Fire off draw event + eventEmitter.emit('draw', { + type: 'slice', + value: dataArray[i], + totalDataSum: totalDataSum, + index: i, + group: seriesGroups[i], + element: path, + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + // If we need to show labels we need to add the label for this slice now if(options.showLabel) { // Position at the labelRadius distance from center and between start and end angle var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i); - seriesGroups[i].elem('text', { + var labelElement = seriesGroups[i].elem('text', { dx: labelPosition.x, dy: labelPosition.y, 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) }, options.classNames.label).text('' + interpolatedValue); + + // Fire off draw event + eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); } // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues @@ -1710,6 +2051,12 @@ } } + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container /** * Updates the chart which currently does a full reconstruction of the SVG DOM * @@ -1731,58 +2078,50 @@ } /** - * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options. + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * * @memberof Chartist.Pie - * @param {Function} callback Callback function that will have the new options as first parameter + * @param {String} event Name of the event. Check the examples for supported events. + * @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. */ - function addOptionsListener(callback) { - optionsProvider.addOptionsListener(callback); + function on(event, handler) { + eventEmitter.addEventHandler(event, handler); } /** - * Remove a responsive options listener that was previously added using the addOptionsListener method. + * 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. * * @memberof Chartist.Pie - * @param {Function} callback The callback function that was registered earlier with addOptionsListener + * @param {String} event Name of the event for which a handler should be removed + * @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. */ - function removeOptionsListener(callback) { - optionsProvider.removeOptionsListener(callback); + function off(event, handler) { + eventEmitter.removeEventHandler(event, handler); } - // If this container already contains chartist, let's try to detach first and unregister all event listeners - if(container.chartist) { - container.chartist.detach(); - } + // Initialization of the chart + + window.addEventListener('resize', update); // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions); - createChart(optionsProvider.currentOptions); - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - function updateChart() { + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { createChart(optionsProvider.currentOptions); - } + }, 0); - window.addEventListener('resize', updateChart); - - // Public members + // Public members of the module (revealing module pattern style) var api = { version: Chartist.version, update: update, - detach: detach, - addOptionsListener: addOptionsListener, - removeOptionsListener: removeOptionsListener + on: on, + off: off, + detach: detach }; container.chartist = api; - return api; }; diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index 2b2b5218..186222be 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,7 +1,7 @@ -/* Chartist.js 0.1.15 +/* Chartist.js 0.2.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -.ct-chart .ct-label{fill:rgba(0,0,0,.4);font-size:.75rem}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.88889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.33333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.66667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.8047%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.33333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.33333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%} \ No newline at end of file +.ct-chart .ct-label{fill:rgba(0,0,0,.4);font-size:.75rem}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%} \ No newline at end of file diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 8732fc25..9a42ae5a 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.1.15 +/* Chartist.js 0.2.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.1.14",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getHeight=function(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight},c.getWidth=function(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b||"100%",height:d||"100%"}).removeAllClasses().addClass(e),f.empty()):(f=c.svg("svg").attr({width:b||"100%",height:d||"100%"}).addClass(e),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return c.getHeight(a._node)-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e])}),a}function i(a,d,e,f,g,i){var j=b.createElementNS(q,d);return"svg"===d&&j.setAttributeNS(r,c.xmlNs.qualifiedName,c.xmlNs.uri),i&&(g&&i.firstChild?i.insertBefore(j,i.firstChild):i.appendChild(j)),e&&h(j,e),f&&n(j,f),j}function j(a,c){a.appendChild(b.createTextNode(c))}function k(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function l(a){a.parentNode.removeChild(a)}function m(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function n(a,b){a.setAttribute("class",m(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function o(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",m(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function p(a){a.setAttribute("class","")}var q="http://www.w3.org/2000/svg",r="http://www.w3.org/2000/xmlns/";return{_node:i(this,a,d,e,f,g?g._node:void 0),_parent:g,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return k(this._node),this},remove:function(){return l(this._node),this},elem:function(a,b,d,e){return c.svg(a,b,d,e,this)},text:function(a){return j(this._node,a),this},addClass:function(a){return n(this._node,a),this},removeClass:function(a){return o(this._node,a),this},removeAllClasses:function(){return p(this._node),this},classes:function(){return m(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);n=c.createSvg(p,a.width,a.height,a.classNames.chart),f=c.getBounds(n,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(n,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,c.getHeight)),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(n,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,c.getWidth));var i=c.createChartRect(n,a,b,e),j=n.elem("g"),k=n.elem("g");c.createXAxis(i,d,k,j,a),c.createYAxis(i,f,k,j,e,a);for(var l=0;l4)for(var t=c.catmullRom2bezier(q),u=0;ua.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);o=c.createSvg(q,a.width,a.height,a.classNames.chart),b=c.createChartRect(o,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=0;m=n-j?"0":"1",t=["M",r.x,r.y,"A",e,e,0,s,0,p.x,p.y];a.donut===!1&&t.push("L",l.x,l.y);var u=i[m].elem("path",{d:t.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(u.attr({value:k[m]},c.xmlNs.uri),a.donut===!0&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),a.showLabel){var v=c.polarToCartesian(l.x,l.y,f,j+(n-j)/2),w=a.labelInterpolationFnc(d.labels?d.labels[m]:k[m],m);i[m].elem("text",{dx:v.x,dy:v.y,"text-anchor":g(l,v,a.labelDirection)},a.classNames.label).text(""+w)}j=n}}function i(){h(n.currentOptions)}function j(){a.removeEventListener("resize",i),n.clear()}function k(a){n.addOptionsListener(a)}function l(a){n.removeOptionsListener(a)}function m(){h(n.currentOptions)}var n,o,p={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},q=c.querySelector(b);q.chartist&&q.chartist.detach(),n=c.optionsProvider(p,e,f),h(n.currentOptions),a.addEventListener("resize",m);var r={version:c.version,update:i,detach:j,addOptionsListener:k,removeOptionsListener:l};return q.chartist=r,r}}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.1.14",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getHeight=function(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight},c.getWidth=function(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b||"100%",height:d||"100%"}).removeAllClasses().addClass(e),f.empty()):(f=c.Svg("svg").attr({width:b||"100%",height:d||"100%"}).addClass(e),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return c.getHeight(a._node)-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(t,a);return"svg"===a&&i.setAttributeNS(u,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",v);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}var t="http://www.w3.org/2000/svg",u="http://www.w3.org/2000/xmlns/",v="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,c.getHeight)),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,c.getWidth));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=0;m=o-j?"0":"1",u=["M",s.x,s.y,"A",e,e,0,t,0,r.x,r.y];a.donut===!1&&u.push("L",l.x,l.y);var v=i[m].elem("path",{d:u.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(v.attr({value:k[m]},c.xmlNs.uri),a.donut===!0&&v.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[m],totalDataSum:h,index:m,group:i[m],element:v,center:l,radius:e,startAngle:j,endAngle:o}),a.showLabel){var w=c.polarToCartesian(l.x,l.y,f,j+(o-j)/2),x=a.labelInterpolationFnc(d.labels?d.labels[m]:k[m],m),y=i[m].elem("text",{dx:w.x,dy:w.y,"text-anchor":g(l,w,a.labelDirection)},a.classNames.label).text(""+x);q.emit("draw",{type:"label",index:m,group:i[m],element:y,text:""+x,x:w.x,y:w.y})}j=o}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.clear()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 36366658..0c07aa2e 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getHeight","svgElement","clientHeight","Math","round","getBBox","height","parentNode","getWidth","clientWidth","width","querySelector","query","Node","createSvg","container","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","empty","appendChild","_node","getDataArray","data","array","i","series","length","normalizeDataArray","dataArray","j","orderOfMagnitude","value","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","forEach","index","interpolatedValue","pos","showGrid","classNames","horizontal","join","showLabel","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCrrentOptions","currentOptions","baseOptions","mql","matchMedia","matches","clearMediaQueryListeners","mediaQueryListeners","removeListener","optionsListeners","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":22840,"pos":22826,"col":12,"line":573,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":22840,"pos":22826,"col":12,"line":573,"value":"currentOptions","type":"name"},"name":"currentOptions"},"addOptionsListener","callback","removeOptionsListener","splice","indexOf","clear","catmullRom2bezier","crp","z","d","iLen","p","xmlNs","qualifiedName","prefix","uri","name","attributes","insertFirst","parent","node","ns","Object","keys","key","setAttributeNS","setAttribute","createElementNS","svgNs","firstChild","insertBefore","t","createTextNode","removeChild","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","_parent","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaPathElements","slice","areaBaseProjected","areaBase","area","line","update","detach","removeEventListener","updateChart","chartist","addEventListener","api","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","endAngle","start","end","arcSweep","path","style","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.1.15\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.1.14';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n //TODO: move into Chartist.svg\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its height\n * @return {Number} The elements height in pixels\n */\n Chartist.getHeight = function (svgElement) {\n return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight;\n };\n\n //TODO: move into Chartist.svg\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its width\n * @return {Number} The elements width in pixels\n */\n Chartist.getWidth = function (svgElement) {\n return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width || '100%',\n height: height || '100%'\n }).removeAllClasses().addClass(className);\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = Chartist.svg('svg').attr({\n width: width || '100%',\n height: height || '100%'\n }).addClass(className);\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, offsetFnc(label._node));\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (options.height || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset,\n x2: (options.width || Chartist.getWidth(svg._node)) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n pos = chartRect.x1 + chartRect.width() / data.labels.length * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var label = labels.elem('text', {\n dx: pos + 2\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n label.attr({\n dy: chartRect.y1 + Chartist.getHeight(label._node) + options.axisX.offset\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n pos = chartRect.y1 - chartRect.height() / bounds.values.length * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n }\n\n if (options.axisY.showLabel) {\n labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\n * @param {Object} options Options set by user\n * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart\n * @param {Function} optionsChangedCallbackFnc The callback that will be executed when a media change triggered new options to be used. The callback function will receive the new options as first parameter.\n * @return {Object} The consolidated options object from the defaults, base and matching responsive options\n */\n Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n optionsListeners = [],\n i;\n\n function updateCrrentOptions() {\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\n function clearMediaQueryListeners() {\n mediaQueryListeners.forEach(function(mql) {\n mql.removeListener(updateCrrentOptions);\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(updateCrrentOptions);\n mediaQueryListeners.push(mql);\n }\n }\n // Execute initially so we get the correct current options\n updateCrrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n addOptionsListener: function(callback) {\n optionsListeners.push(callback);\n },\n removeOptionsListener: function(callback) {\n optionsListeners.splice(optionsListeners.indexOf(callback), 1);\n },\n clear: function() {\n optionsListeners = [];\n clearMediaQueryListeners();\n }\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\n\n Chartist.svg = function(name, attributes, className, insertFirst, parent) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/';\n\n function attr(node, attributes, ns) {\n Object.keys(attributes).forEach(function(key) {\n if(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\n }\n\n function elem(svg, name, attributes, className, insertFirst, parentNode) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return node;\n }\n\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\n }\n\n function remove(node) {\n node.parentNode.removeChild(node);\n }\n\n function classes(node) {\n return node.getAttribute('class') ? node.getAttribute('class').trim().split(/\\s+/) : [];\n }\n\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\n }\n\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n return {\n _node: elem(this, name, attributes, className, insertFirst, parent ? parent._node : undefined),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.svg(name, attributes, className, insertFirst, this);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns an object handle to the internal closure. Currently you can use the returned object only for updating / redrawing the 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 with a version and an update method to manually redraw the chart\n *\n * @example\n * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Line\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Line\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Line\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 function updateChart() {\n createChart(optionsProvider.currentOptions);\n }\n\n window.addEventListener('resize', updateChart);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\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 * This method creates a new bar chart and returns an object handle with delegations to the internal closure of the bar chart. You can use the returned object to redraw the chart.\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 with a version and an update method to manually redraw the chart\n *\n * @example\n * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with SASS and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Bar\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Bar\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Bar\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 window.addEventListener('resize', update);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg;\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // If we need to show labels we need to add the label for this slice now\n if(options.showLabel) {\n // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n seriesGroups[i].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\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\n\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\n }\n\n /**\n * Add a listener for the responsive options updates. Once the chart will switch to a new option set the listener will be called with the new options.\n *\n * @memberof Chartist.Pie\n * @param {Function} callback Callback function that will have the new options as first parameter\n */\n function addOptionsListener(callback) {\n optionsProvider.addOptionsListener(callback);\n }\n\n /**\n * Remove a responsive options listener that was previously added using the addOptionsListener method.\n *\n * @memberof Chartist.Pie\n * @param {Function} callback The callback function that was registered earlier with addOptionsListener\n */\n function removeOptionsListener(callback) {\n optionsProvider.removeOptionsListener(callback);\n }\n\n // If this container already contains chartist, let's try to detach first and unregister all event listeners\n if(container.chartist) {\n container.chartist.detach();\n }\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions);\n createChart(optionsProvider.currentOptions);\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 function updateChart() {\n createChart(optionsProvider.currentOptions);\n }\n\n window.addEventListener('resize', updateChart);\n\n // Public members\n var api = {\n version: Chartist.version,\n update: update,\n detach: detach,\n addOptionsListener: addOptionsListener,\n removeOptionsListener: removeOptionsListener\n };\n\n container.chartist = api;\n\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getHeight","svgElement","clientHeight","Math","round","getBBox","height","parentNode","getWidth","clientWidth","width","querySelector","query","Node","createSvg","container","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","length","normalizeDataArray","dataArray","j","orderOfMagnitude","value","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24954,"pos":24940,"col":12,"line":645,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24954,"pos":24940,"col":12,"line":645,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","replace","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaPathElements","slice","areaBaseProjected","areaBase","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","clear","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","endAngle","start","end","arcSweep","path","style","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.0\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.1.14';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its height\n * @return {Number} The elements height in pixels\n */\n Chartist.getHeight = function (svgElement) {\n return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its width\n * @return {Number} The elements width in pixels\n */\n Chartist.getWidth = function (svgElement) {\n return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width || '100%',\n height: height || '100%'\n }).removeAllClasses().addClass(className);\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = Chartist.Svg('svg').attr({\n width: width || '100%',\n height: height || '100%'\n }).addClass(className);\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, offsetFnc(label._node));\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (options.height || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset,\n x2: (options.width || Chartist.getWidth(svg._node)) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with SASS and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index 3691ea43..28c2e522 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.1.15", + "version": "0.2.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 9afd57151344a16e99ce97a3e9c568c27d98247b Mon Sep 17 00:00:00 2001 From: Callum Macdonald Date: Sun, 5 Oct 2014 18:34:03 +0200 Subject: [PATCH 015/593] Small grammar corrections --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2dd8c276..503bbb8a 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,17 @@ out there, but they are either: * have unnecessary dependencies to monolithic libraries * more annoying things -That's why we have started Chartist.js and our goal is to solve all of the above issues. +That's why we started Chartist.js and our goal is to solve all of the above issues. ## What is it made for? -Chartist's goal is to provide a simple, lightweight and non-intrusive library to responsive craft charts on your website. +Chartist's goal is to provide a simple, lightweight and unintrusive library to responsively craft charts on your website. It's important to understand that one of the main intentions of Chartist.js is to rely on standards rather than providing -a own solution to the problem which is already solved by the standard. We need to leverage the power of the browsers +it's own solution to a problem which is already solved by those standards. We need to leverage the power of browsers today and say good bye to the idea of solving all problems ourselves. Chartist works with inline-SVG and therefore leverages the power of the DOM to provide parts of its functionality. This -also means that Chartist is not providing it's own event handling, labels, behaviors and anything else that can just be +also means that Chartist does not provide it's own event handling, labels, behaviors or anything else that can just be done with plain HTML, JavaScript and CSS. The single and only responsibility of Chartist is to help you drawing "Simple responsive Charts" using inline-SVG in the DOM, CSS to style and JavaScript to provide an API for configuring your charts. From 8f6663a1680825b9567284cf4ef53bf453cb5b1f Mon Sep 17 00:00:00 2001 From: Victor Carreon Date: Mon, 6 Oct 2014 13:16:44 -0500 Subject: [PATCH 016/593] Fix for donut chart so that when a series only has one non-zero value, it still calculates the correct starting angle --- source/scripts/chartist.pie.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index b36b6291..b2833c6c 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -166,6 +166,9 @@ y: chartRect.y2 + chartRect.height() / 2 }; + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = data.series.filter(function(val) { return val !== 0; }).length === 1; + // Draw the series // initialize series groups for (var i = 0; i < data.series.length; i++) { @@ -191,7 +194,7 @@ endAngle -= 0.01; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 ? 0 : 0.2)), + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), arcSweep = endAngle - startAngle <= 180 ? '0' : '1', d = [ From 5406e3cfab1485be596c99288e84b16a4a6d0e28 Mon Sep 17 00:00:00 2001 From: Victor Carreon Date: Mon, 6 Oct 2014 13:46:24 -0500 Subject: [PATCH 017/593] putting function onto new line --- source/scripts/chartist.pie.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index b2833c6c..6b2f5c85 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -167,7 +167,9 @@ }; // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = data.series.filter(function(val) { return val !== 0; }).length === 1; + var hasSingleValInSeries = data.series.filter(function(val) { + return val !== 0; + }).length === 1; // Draw the series // initialize series groups From a6178a54d063eaad75b1a0dede49f8abda3380b5 Mon Sep 17 00:00:00 2001 From: Una Kravets Date: Tue, 7 Oct 2014 21:26:23 -0500 Subject: [PATCH 018/593] Sass, not SASS -- and added presentation ARIA role to tables --- CODINGSTYLE.md | 16 ++++++++-------- CONTRIBUTING.md | 2 +- README.md | 2 +- libdist/chartist.js | 2 +- source/scripts/chartist.bar.js | 2 +- source/site/data/pages/getting-started.yml | 22 +++++++++++----------- source/site/index.hbs | 4 ++-- source/site/partials/table.hbs | 4 ++-- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/CODINGSTYLE.md b/CODINGSTYLE.md index c7011668..a9bda642 100644 --- a/CODINGSTYLE.md +++ b/CODINGSTYLE.md @@ -1,8 +1,8 @@ -# Web Styleguide - Style guide to harmonize HTML, Javascript and CSS / SASS coding style +# Web Styleguide - Style guide to harmonize HTML, Javascript and CSS / Sass coding style This document defines formatting and style rules for HTML, Javascript and CSS / SCSS. It aims at improving collaboration, code quality, and enabling supporting infrastructure. It applies to raw, working files that use HTML, -Javascript and CSS, including SASS (SCSS) files. +Javascript and CSS, including Sass (SCSS) files. If a group of developers start to use a style guide, errors become more obvious. If a certain parts of code are not complying with the style guide it could be a style error but it could also be a bug. This makes it easier to review @@ -1799,7 +1799,7 @@ return x === 10 ? 'valid' : 'invalid'; *** -## CSS and SASS (SCSS) style rules +## CSS and Sass (SCSS) style rules *** @@ -2228,7 +2228,7 @@ body:after { ### Nested selectors (SCSS) -In SASS you can nest selectors which is much cleaner and the code becomes much more readable. Nest all selectors but +In Sass you can nest selectors which is much cleaner and the code becomes much more readable. Nest all selectors but try to avoid nesting without any content. If you need to specify some style attributes for a child element where the parent element will not receive any styling use a regular CSS selector chain. This will prevent your script to look overcomplicated. @@ -2317,7 +2317,7 @@ If you nest your selectors introduce blank line between your nested selectors an ### Contextual media queries (SCSS) -While nesting your selectors you can also make use of contextual media queries within SASS. With SASS you can use media +While nesting your selectors you can also make use of contextual media queries within Sass. With Sass you can use media queries at any given nesting level. The resulting CSS will be converted so that the media query gets rendered around the selector. @@ -2428,17 +2428,17 @@ them in order to provide the desktop styles. ### Nesting order and the parent selector (SCSS) -While using the nesting features of SASS it's important to have a clear order to put your nesting in. A SCSS block +While using the nesting features of Sass it's important to have a clear order to put your nesting in. A SCSS block should have the following content order. 1. Current selector's style attributes 1. Pseudo selectors with parent selector (:first-letter, :hover, :active etc) 1. Pseudo elements (:before and :after) 1. State classe with parent selector (.selected, .active, .enlarged etc.) -1. Contextual media queries with SASS +1. Contextual media queries with Sass 1. Sub selectors as the last part -The following example should illustrate how this ordering will achieve a clear structure while making use of the SASS +The following example should illustrate how this ordering will achieve a clear structure while making use of the Sass parent selector. **Recommended** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bfbbf637..529c9ba1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,5 +57,5 @@ We have three grunt tasks: 2. Documentation: JSDoc, Getting started documentation and landing page 3. Better accessibility using ARIA and other optimizations 4. Better interfaces to the library (i.e. jQuery with data-* attributes for configuration), Angular.js directive etc. -5. Richer SASS / CSS framework +5. Richer Sass / CSS framework 6. Other charts types (spider etc.) diff --git a/README.md b/README.md index 503bbb8a..12f64c49 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ to the masses. 2. Documentation: JSDoc, Getting started documentation and landing page 3. Better accessibility using ARIA and other optimizations 4. Better interfaces to the library (i.e. jQuery with data-* attributes for configuration), Angular.js directive etc. -5. Richer SASS / CSS framework +5. Richer Sass / CSS framework 6. Other charts types (spider etc.) ## Contribution diff --git a/libdist/chartist.js b/libdist/chartist.js index d1dd873c..747be28c 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -1680,7 +1680,7 @@ bar; // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with SASS and semantic / specific selectors + // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors p.x += periodHalfWidth + (biPol * options.seriesBarDistance); bar = seriesGroups[i].elem('line', { diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 31e1037f..b010b35c 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -217,7 +217,7 @@ bar; // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with SASS and semantic / specific selectors + // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors p.x += periodHalfWidth + (biPol * options.seriesBarDistance); bar = seriesGroups[i].elem('line', { diff --git a/source/site/data/pages/getting-started.yml b/source/site/data/pages/getting-started.yml index bea403d2..f9723655 100644 --- a/source/site/data/pages/getting-started.yml +++ b/source/site/data/pages/getting-started.yml @@ -19,7 +19,7 @@ sections: - type: text data: text: > - The bower package contains the JavaScript library, CSS as well as the SASS (SCSS) files. + The bower package contains the JavaScript library, CSS as well as the Sass (SCSS) files. You can then integrate the desired dependencies in your project and start using them immediately. @@ -32,9 +32,9 @@ sections: data: text: > The quickest way to get things up and running is by using the Chartist.js CSS files. - The CSS is compiled from the SASS files with the default class names which are also + The CSS is compiled from the Sass files with the default class names which are also configured in the JavaScript library. You can then override the default styles or - modify the CSS file, however, for customization it's recommended to use the SASS + modify the CSS file, however, for customization it's recommended to use the Sass version of Chartist.js. - type: code-snippet @@ -44,28 +44,28 @@ sections: - type: sub-section data: - title: The SASS way + title: The Sass way level: 4 items: - type: text data: text: > If you like to customize your charts you can either remove the CSS fully and write your - own selectors using the Chartist.js SASS mixins or you just use the Chartist.js SASS + own selectors using the Chartist.js Sass mixins or you just use the Chartist.js Sass settings file to customize the look and feel of your charts. - type: text data: text: > Styling inline SVG with CSS is a breeze and you should also consider writing your own - selectors for your charts and using the SASS mixins. You can read more about using the - SASS mixins in the advanced section. + selectors for your charts and using the Sass mixins. You can read more about using the + Sass mixins in the advanced section. - type: text data: text: > - To customize the style of your charts using the SASS settings file you should copy the - settings file to your own SASS folder. + To customize the style of your charts using the Sass settings file you should copy the + settings file to your own Sass folder. - type: code data: @@ -104,7 +104,7 @@ sections: - type: code-snippet data: - id: default-sass-settings + id: default-Sass-settings button: Show default settings path: source/styles/settings/_chartist-settings.scss lang: scss @@ -163,7 +163,7 @@ sections: - type: text data: text: > - Here is a list of all available container ratios (If using the SASS version of Chartist you can also easily add others): + Here is a list of all available container ratios (If using the Sass version of Chartist you can also easily add others): - type: table data: diff --git a/source/site/index.hbs b/source/site/index.hbs index 2e6010ac..fc801d5b 100644 --- a/source/site/index.hbs +++ b/source/site/index.hbs @@ -26,9 +26,9 @@ of other great charting libraries but after using them there were always tweaks
  • Usage of SVG (Yes! SVG is the future of illustration in web!)
  • Fully responsive and DPI independent
  • Responsive configuration with media queries
  • -
  • Fully built and customizable with SASS
  • +
  • Fully built and customizable with Sass
  • {{#each page.sections}} {{>section}} -{{/each}} \ No newline at end of file +{{/each}} diff --git a/source/site/partials/table.hbs b/source/site/partials/table.hbs index 1f295202..51ee59e0 100644 --- a/source/site/partials/table.hbs +++ b/source/site/partials/table.hbs @@ -1,5 +1,5 @@ {{#if button}}{{button}}{{/if}} - +
    {{#if header}} @@ -19,4 +19,4 @@ {{/each}} - \ No newline at end of file + From 85e60b6fe81d6eff74f6d12f4604cc86611be0f6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 8 Oct 2014 18:23:40 +0200 Subject: [PATCH 019/593] In order to use string values in width and height, we always need to calculate the computed size of the SVG element and also remove the width / height styles --- source/scripts/chartist.core.js | 4 ++-- source/styles/chartist.scss | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 20afd1b8..070aac72 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -388,8 +388,8 @@ Chartist.version = '0.1.14'; Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) { return { x1: options.chartPadding + yAxisOffset, - y1: (options.height || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset, - x2: (options.width || Chartist.getWidth(svg._node)) - options.chartPadding, + y1: Chartist.getHeight(svg._node) - options.chartPadding - xAxisOffset, + x2: Chartist.getWidth(svg._node) - options.chartPadding, y2: options.chartPadding, width: function () { return this.x2 - this.x1; diff --git a/source/styles/chartist.scss b/source/styles/chartist.scss index e7b6699a..a31d95a6 100644 --- a/source/styles/chartist.scss +++ b/source/styles/chartist.scss @@ -26,8 +26,6 @@ position: absolute; top: 0; left: 0; - width: 100%; - height: 100%; } } From e0f1008ea834bc79ae4cf115daa43d2d7754b7b0 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 8 Oct 2014 18:48:44 +0200 Subject: [PATCH 020/593] Fixed trailing whitespace --- source/scripts/chartist.pie.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index 6b2f5c85..c3a89391 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -167,8 +167,8 @@ }; // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = data.series.filter(function(val) { - return val !== 0; + var hasSingleValInSeries = data.series.filter(function(val) { + return val !== 0; }).length === 1; // Draw the series From 69c39259c7517a5bce5c1fae09f29803a507b191 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 8 Oct 2014 18:51:01 +0200 Subject: [PATCH 021/593] Let's get rid of IE8 :-) --- bower.json | 2 -- source/site/layouts/default.hbs | 11 ----------- 2 files changed, 13 deletions(-) diff --git a/bower.json b/bower.json index 4ceaa764..68b49b79 100644 --- a/bower.json +++ b/bower.json @@ -7,8 +7,6 @@ ], "devDependencies": { "snap.svg": "~0.2.0", - "json3": "~3.2.6", - "es5-shim": "~2.1.0", "foundation": "~5.1.1", "highlightjs": "~8.0.0", "compass-mixins": "~1.0.0", diff --git a/source/site/layouts/default.hbs b/source/site/layouts/default.hbs index 82b24a34..179d147f 100644 --- a/source/site/layouts/default.hbs +++ b/source/site/layouts/default.hbs @@ -23,10 +23,6 @@ - {{> body }} @@ -41,13 +37,6 @@ ga('send', 'pageview'); - - - - - - From 45433b52a37027c5396d05b4c7f602361f61c356 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 8 Oct 2014 20:17:32 +0200 Subject: [PATCH 022/593] Added explicit width / height for chartist guy on landing page --- source/styles/site/_landing.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/styles/site/_landing.scss b/source/styles/site/_landing.scss index ccf0ff6d..d8e8ad20 100644 --- a/source/styles/site/_landing.scss +++ b/source/styles/site/_landing.scss @@ -34,6 +34,11 @@ > figure { @include ct-responsive-svg-container($ratio: (1/1)); + + > svg { + width: 100%; + height: 100%; + } } } From 14890a9ee8ce714679c9ad03f1026c1e6a5614d6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 8 Oct 2014 20:18:25 +0200 Subject: [PATCH 023/593] Using configured width / height when specified in pixel --- source/scripts/chartist.core.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 070aac72..a4dae084 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -78,6 +78,20 @@ Chartist.version = '0.1.14'; return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth; }; + /** + * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified. + * + * @param {String|Number} length + * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel + */ + Chartist.getPixelLength = function(length) { + if(typeof length === 'string') { + length = length.replace(/px/i, ''); + } + + return +length; + }; + /** * This is a wrapper around document.querySelector that will return the query if it's already of type Node * @@ -388,8 +402,8 @@ Chartist.version = '0.1.14'; Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) { return { x1: options.chartPadding + yAxisOffset, - y1: Chartist.getHeight(svg._node) - options.chartPadding - xAxisOffset, - x2: Chartist.getWidth(svg._node) - options.chartPadding, + y1: (Chartist.getPixelLength(options.height) || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset, + x2: (Chartist.getPixelLength(options.width) ||Chartist.getWidth(svg._node)) - options.chartPadding, y2: options.chartPadding, width: function () { return this.x2 - this.x1; From e8db7e50070e666fa0dfa8e21fdf221c4938f34a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 8 Oct 2014 20:33:08 +0200 Subject: [PATCH 024/593] Added CDN documentation and how to use jsDelivr to get started with Chartist --- .../site/code-snippets/simple-start-cdn.html | 7 +++++++ source/site/data/pages/getting-started.yml | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 source/site/code-snippets/simple-start-cdn.html diff --git a/source/site/code-snippets/simple-start-cdn.html b/source/site/code-snippets/simple-start-cdn.html new file mode 100644 index 00000000..8ae6a735 --- /dev/null +++ b/source/site/code-snippets/simple-start-cdn.html @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/source/site/data/pages/getting-started.yml b/source/site/data/pages/getting-started.yml index f9723655..81c1f7cf 100644 --- a/source/site/data/pages/getting-started.yml +++ b/source/site/data/pages/getting-started.yml @@ -42,6 +42,26 @@ sections: id: simple-start lang: html + - type: heading + data: + level: 5 + title: Use a CDN alternatively + + - type: text + data: + text: > + If you'd like to get started even faster you can also use a CDN to load Chartist.js. The + awesome people at jsDelivr provide a fantastic job in hosting libraries from over 42 POP Locations + around the world! They always update Chartist.js to the latest version immediately and + they do all that for free! Check out the jsDeliver website + for more information. + + - type: code-snippet + data: + id: simple-start-cdn + lang: html + button: Show CDN Code + - type: sub-section data: title: The Sass way From 6b8bd0556ebc35af830239a87e44651cfb1346b7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 8 Oct 2014 20:40:19 +0200 Subject: [PATCH 025/593] Updated to version 0.2.1 --- bower.json | 2 +- libdist/chartist.js | 27 +++++++++++++++++++++++---- libdist/chartist.min.css | 4 ++-- libdist/chartist.min.js | 4 ++-- libdist/chartist.min.map | 2 +- libdist/scss/chartist.scss | 2 -- package.json | 2 +- 7 files changed, 30 insertions(+), 13 deletions(-) diff --git a/bower.json b/bower.json index 68b49b79..56f753d6 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.2.0", + "version": "0.2.1", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index 747be28c..63075a70 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.2.0 + /* Chartist.js 0.2.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -95,6 +95,20 @@ return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth; }; + /** + * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified. + * + * @param {String|Number} length + * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel + */ + Chartist.getPixelLength = function(length) { + if(typeof length === 'string') { + length = length.replace(/px/i, ''); + } + + return +length; + }; + /** * This is a wrapper around document.querySelector that will return the query if it's already of type Node * @@ -405,8 +419,8 @@ Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) { return { x1: options.chartPadding + yAxisOffset, - y1: (options.height || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset, - x2: (options.width || Chartist.getWidth(svg._node)) - options.chartPadding, + y1: (Chartist.getPixelLength(options.height) || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset, + x2: (Chartist.getPixelLength(options.width) ||Chartist.getWidth(svg._node)) - options.chartPadding, y2: options.chartPadding, width: function () { return this.x2 - this.x1; @@ -1949,6 +1963,11 @@ y: chartRect.y2 + chartRect.height() / 2 }; + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = data.series.filter(function(val) { + return val !== 0; + }).length === 1; + // Draw the series // initialize series groups for (var i = 0; i < data.series.length; i++) { @@ -1974,7 +1993,7 @@ endAngle -= 0.01; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 ? 0 : 0.2)), + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), arcSweep = endAngle - startAngle <= 180 ? '0' : '1', d = [ diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index 186222be..ac89789f 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,7 +1,7 @@ -/* Chartist.js 0.2.0 +/* Chartist.js 0.2.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -.ct-chart .ct-label{fill:rgba(0,0,0,.4);font-size:.75rem}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0;width:100%;height:100%} \ No newline at end of file +.ct-chart .ct-label{fill:rgba(0,0,0,.4);font-size:.75rem}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 9a42ae5a..4b7148bf 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.2.0 +/* Chartist.js 0.2.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.1.14",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getHeight=function(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight},c.getWidth=function(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b||"100%",height:d||"100%"}).removeAllClasses().addClass(e),f.empty()):(f=c.Svg("svg").attr({width:b||"100%",height:d||"100%"}).addClass(e),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return c.getHeight(a._node)-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(t,a);return"svg"===a&&i.setAttributeNS(u,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",v);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}var t="http://www.w3.org/2000/svg",u="http://www.w3.org/2000/xmlns/",v="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,c.getHeight)),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,c.getWidth));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=0;m=o-j?"0":"1",u=["M",s.x,s.y,"A",e,e,0,t,0,r.x,r.y];a.donut===!1&&u.push("L",l.x,l.y);var v=i[m].elem("path",{d:u.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(v.attr({value:k[m]},c.xmlNs.uri),a.donut===!0&&v.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[m],totalDataSum:h,index:m,group:i[m],element:v,center:l,radius:e,startAngle:j,endAngle:o}),a.showLabel){var w=c.polarToCartesian(l.x,l.y,f,j+(o-j)/2),x=a.labelInterpolationFnc(d.labels?d.labels[m]:k[m],m),y=i[m].elem("text",{dx:w.x,dy:w.y,"text-anchor":g(l,w,a.labelDirection)},a.classNames.label).text(""+x);q.emit("draw",{type:"label",index:m,group:i[m],element:y,text:""+x,x:w.x,y:w.y})}j=o}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.clear()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.1.14",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getHeight=function(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight},c.getWidth=function(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b||"100%",height:d||"100%"}).removeAllClasses().addClass(e),f.empty()):(f=c.Svg("svg").attr({width:b||"100%",height:d||"100%"}).addClass(e),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return c.getHeight(a._node)-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(t,a);return"svg"===a&&i.setAttributeNS(u,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",v);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}var t="http://www.w3.org/2000/svg",u="http://www.w3.org/2000/xmlns/",v="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,c.getHeight)),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,c.getWidth));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===d.series.filter(function(a){return 0!==a}).length,o=0;o=r-j?"0":"1",v=["M",t.x,t.y,"A",e,e,0,u,0,s.x,s.y];a.donut===!1&&v.push("L",l.x,l.y);var w=i[o].elem("path",{d:v.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(w.attr({value:k[o]},c.xmlNs.uri),a.donut===!0&&w.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[o],totalDataSum:h,index:o,group:i[o],element:w,center:l,radius:e,startAngle:j,endAngle:r}),a.showLabel){var x=c.polarToCartesian(l.x,l.y,f,j+(r-j)/2),y=a.labelInterpolationFnc(d.labels?d.labels[o]:k[o],o),z=i[o].elem("text",{dx:x.x,dy:x.y,"text-anchor":g(l,x,a.labelDirection)},a.classNames.label).text(""+y);q.emit("draw",{type:"label",index:o,group:i[o],element:z,text:""+y,x:x.x,y:x.y})}j=r}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.clear()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 0c07aa2e..23027d43 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getHeight","svgElement","clientHeight","Math","round","getBBox","height","parentNode","getWidth","clientWidth","width","querySelector","query","Node","createSvg","container","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","length","normalizeDataArray","dataArray","j","orderOfMagnitude","value","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24954,"pos":24940,"col":12,"line":645,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24954,"pos":24940,"col":12,"line":645,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","replace","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaPathElements","slice","areaBaseProjected","areaBase","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","clear","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","endAngle","start","end","arcSweep","path","style","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.0\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.1.14';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its height\n * @return {Number} The elements height in pixels\n */\n Chartist.getHeight = function (svgElement) {\n return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its width\n * @return {Number} The elements width in pixels\n */\n Chartist.getWidth = function (svgElement) {\n return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width || '100%',\n height: height || '100%'\n }).removeAllClasses().addClass(className);\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = Chartist.Svg('svg').attr({\n width: width || '100%',\n height: height || '100%'\n }).addClass(className);\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, offsetFnc(label._node));\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (options.height || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset,\n x2: (options.width || Chartist.getWidth(svg._node)) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with SASS and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getHeight","svgElement","clientHeight","Math","round","getBBox","height","parentNode","getWidth","clientWidth","width","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":25484,"pos":25470,"col":12,"line":659,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":25484,"pos":25470,"col":12,"line":659,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaPathElements","slice","areaBaseProjected","areaBase","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","clear","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","style","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.1.14';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its height\n * @return {Number} The elements height in pixels\n */\n Chartist.getHeight = function (svgElement) {\n return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its width\n * @return {Number} The elements width in pixels\n */\n Chartist.getWidth = function (svgElement) {\n return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width || '100%',\n height: height || '100%'\n }).removeAllClasses().addClass(className);\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = Chartist.Svg('svg').attr({\n width: width || '100%',\n height: height || '100%'\n }).addClass(className);\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, offsetFnc(label._node));\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) ||Chartist.getWidth(svg._node)) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/libdist/scss/chartist.scss b/libdist/scss/chartist.scss index e7b6699a..a31d95a6 100644 --- a/libdist/scss/chartist.scss +++ b/libdist/scss/chartist.scss @@ -26,8 +26,6 @@ position: absolute; top: 0; left: 0; - width: 100%; - height: 100%; } } diff --git a/package.json b/package.json index 28c2e522..233fed8a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.2.0", + "version": "0.2.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 0219e75de28e4ab80a9ec8bbb602607575877c60 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 13 Oct 2014 23:01:19 +0200 Subject: [PATCH 026/593] Fix for Safari 7 where we also need to write SVG width / height as style attributes for the chartist responsive containers to work properly. Fixes #68 --- source/scripts/chartist.core.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index a4dae084..4956dbc7 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -116,21 +116,28 @@ Chartist.version = '0.1.14'; Chartist.createSvg = function (container, width, height, className) { var svg; + width = width || '100%'; + height = height || '100%'; + // If already contains our svg object we clear it, set width / height and return if (container.chartistSvg !== undefined) { svg = container.chartistSvg.attr({ - width: width || '100%', - height: height || '100%' - }).removeAllClasses().addClass(className); + width: width, + height: height + }).removeAllClasses().addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); // Clear the draw if its already used before so we start fresh svg.empty(); } else { // Create svg object with width and height or use 100% as default svg = Chartist.Svg('svg').attr({ - width: width || '100%', - height: height || '100%' - }).addClass(className); + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); // Add the DOM node to our container container.appendChild(svg._node); From b7ba992c9dfb3a6490e113f576058a0f322231aa Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 13 Oct 2014 23:09:40 +0200 Subject: [PATCH 027/593] Limitting areaBase into range of bounds low / high so that the area is never spaning outside the chart canvas. Fixes #65 --- source/scripts/chartist.line.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 09c636cd..6cc24b46 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -295,10 +295,15 @@ } if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); + // If we need to draw area shapes we just make a copy of our pathElements SVG path array var areaPathElements = pathElements.slice(); + // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0); + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); // And splice our new area path array to add the missing path elements to close the area shape areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; From 42364496700dd16b3049fc81959057536bcc3180 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 13 Oct 2014 23:35:42 +0200 Subject: [PATCH 028/593] Refactored code to move getHeight and getWidth into Chartist.Svg where it can be called as non-chainable function on elements, fixes parts of #51 --- source/scripts/chartist.bar.js | 4 ++-- source/scripts/chartist.core.js | 38 ++++++--------------------------- source/scripts/chartist.line.js | 4 ++-- source/scripts/chartist.svg.js | 28 ++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index b010b35c..fd7edce7 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -164,7 +164,7 @@ data.labels, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisX.labelInterpolationFnc, - Chartist.getHeight + 'height' ); } @@ -175,7 +175,7 @@ bounds.values, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisY.labelInterpolationFnc, - Chartist.getWidth + 'width' ); } diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 4956dbc7..7dcc5ac6 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -52,32 +52,6 @@ Chartist.version = '0.1.14'; return target; }; - //TODO: move into Chartist.Svg - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @param {Node} svgElement The svg element from which we want to retrieve its height - * @return {Number} The elements height in pixels - */ - Chartist.getHeight = function (svgElement) { - return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight; - }; - - //TODO: move into Chartist.Svg - /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @param {Node} svgElement The svg element from which we want to retrieve its width - * @return {Number} The elements width in pixels - */ - Chartist.getWidth = function (svgElement) { - return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth; - }; - /** * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified. * @@ -224,7 +198,7 @@ Chartist.version = '0.1.14'; * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset; + return svg.height() - (options.chartPadding * 2) - options.axisX.offset; }; /** @@ -351,7 +325,7 @@ Chartist.version = '0.1.14'; * @param {Array} data The array that contains the data to be visualized in the chart * @param {Object} labelClass All css classes of the label * @param {Function} labelInterpolationFnc The function that interpolates the label value - * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context + * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length * @return {Number} The number that represents the label offset in pixels */ Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) { @@ -369,7 +343,7 @@ Chartist.version = '0.1.14'; }, labelClass).text('' + interpolated); // Check if this is the largest label and update offset - offset = Math.max(offset, offsetFnc(label._node)); + offset = Math.max(offset, label[offsetFnc]()); // Remove label after offset Calculation label.remove(); } @@ -409,8 +383,8 @@ Chartist.version = '0.1.14'; Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) { return { x1: options.chartPadding + yAxisOffset, - y1: (Chartist.getPixelLength(options.height) || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset, - x2: (Chartist.getPixelLength(options.width) ||Chartist.getWidth(svg._node)) - options.chartPadding, + y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset, + x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, y2: options.chartPadding, width: function () { return this.x2 - this.x1; @@ -477,7 +451,7 @@ Chartist.version = '0.1.14'; }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue); // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos - labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset; + labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset; labelElement.attr({ dy: labelPos.y }); diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 6cc24b46..d9abbb61 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -203,7 +203,7 @@ data.labels, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisX.labelInterpolationFnc, - Chartist.getHeight + 'height' ); } @@ -214,7 +214,7 @@ bounds.values, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisY.labelInterpolationFnc, - Chartist.getWidth + 'width' ); } diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index 17f9ee76..fa0afe55 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -244,6 +244,28 @@ node.setAttribute('class', ''); } + /** + * Get element height with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Svg + * @return {Number} The elements height in pixels + */ + function height(node) { + return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight; + } + + /** + * Get element width with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + function width(node) { + return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth; + } + return { _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), _parent: parent, @@ -296,6 +318,12 @@ }, classes: function() { return classes(this._node); + }, + height: function() { + return height(this._node); + }, + width: function() { + return width(this._node); } }; }; From afe23c18a10f7befac7d3fba2abe63cf9e61b848 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 13 Oct 2014 23:40:25 +0200 Subject: [PATCH 029/593] Updated to 0.2.2 --- bower.json | 2 +- libdist/chartist.js | 104 ++++++++++++++++++-------------- libdist/chartist.min.css | 2 +- libdist/chartist.min.js | 4 +- libdist/chartist.min.map | 2 +- package.json | 2 +- source/scripts/chartist.core.js | 2 +- 7 files changed, 66 insertions(+), 52 deletions(-) diff --git a/bower.json b/bower.json index 56f753d6..4d49a688 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.2.1", + "version": "0.2.2", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index 63075a70..3c15a2b8 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.2.1 + /* Chartist.js 0.2.2 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -21,7 +21,7 @@ * @module Chartist.Core */ var Chartist = {}; - Chartist.version = '0.1.14'; + Chartist.version = '0.2.2'; (function (window, document, Chartist) { 'use strict'; @@ -69,32 +69,6 @@ return target; }; - //TODO: move into Chartist.Svg - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @param {Node} svgElement The svg element from which we want to retrieve its height - * @return {Number} The elements height in pixels - */ - Chartist.getHeight = function (svgElement) { - return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight; - }; - - //TODO: move into Chartist.Svg - /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @param {Node} svgElement The svg element from which we want to retrieve its width - * @return {Number} The elements width in pixels - */ - Chartist.getWidth = function (svgElement) { - return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth; - }; - /** * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified. * @@ -133,21 +107,28 @@ Chartist.createSvg = function (container, width, height, className) { var svg; + width = width || '100%'; + height = height || '100%'; + // If already contains our svg object we clear it, set width / height and return if (container.chartistSvg !== undefined) { svg = container.chartistSvg.attr({ - width: width || '100%', - height: height || '100%' - }).removeAllClasses().addClass(className); + width: width, + height: height + }).removeAllClasses().addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); // Clear the draw if its already used before so we start fresh svg.empty(); } else { // Create svg object with width and height or use 100% as default svg = Chartist.Svg('svg').attr({ - width: width || '100%', - height: height || '100%' - }).addClass(className); + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); // Add the DOM node to our container container.appendChild(svg._node); @@ -234,7 +215,7 @@ * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset; + return svg.height() - (options.chartPadding * 2) - options.axisX.offset; }; /** @@ -361,7 +342,7 @@ * @param {Array} data The array that contains the data to be visualized in the chart * @param {Object} labelClass All css classes of the label * @param {Function} labelInterpolationFnc The function that interpolates the label value - * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context + * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length * @return {Number} The number that represents the label offset in pixels */ Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) { @@ -379,7 +360,7 @@ }, labelClass).text('' + interpolated); // Check if this is the largest label and update offset - offset = Math.max(offset, offsetFnc(label._node)); + offset = Math.max(offset, label[offsetFnc]()); // Remove label after offset Calculation label.remove(); } @@ -419,8 +400,8 @@ Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) { return { x1: options.chartPadding + yAxisOffset, - y1: (Chartist.getPixelLength(options.height) || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset, - x2: (Chartist.getPixelLength(options.width) ||Chartist.getWidth(svg._node)) - options.chartPadding, + y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset, + x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, y2: options.chartPadding, width: function () { return this.x2 - this.x1; @@ -487,7 +468,7 @@ }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue); // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos - labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset; + labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset; labelElement.attr({ dy: labelPos.y }); @@ -1020,6 +1001,28 @@ node.setAttribute('class', ''); } + /** + * Get element height with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Svg + * @return {Number} The elements height in pixels + */ + function height(node) { + return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight; + } + + /** + * Get element width with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + function width(node) { + return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth; + } + return { _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), _parent: parent, @@ -1072,6 +1075,12 @@ }, classes: function() { return classes(this._node); + }, + height: function() { + return height(this._node); + }, + width: function() { + return width(this._node); } }; }; @@ -1281,7 +1290,7 @@ data.labels, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisX.labelInterpolationFnc, - Chartist.getHeight + 'height' ); } @@ -1292,7 +1301,7 @@ bounds.values, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisY.labelInterpolationFnc, - Chartist.getWidth + 'width' ); } @@ -1373,10 +1382,15 @@ } if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); + // If we need to draw area shapes we just make a copy of our pathElements SVG path array var areaPathElements = pathElements.slice(); + // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0); + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); // And splice our new area path array to add the missing path elements to close the area shape areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; @@ -1641,7 +1655,7 @@ data.labels, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisX.labelInterpolationFnc, - Chartist.getHeight + 'height' ); } @@ -1652,7 +1666,7 @@ bounds.values, [options.classNames.label, options.classNames.horizontal].join(' '), options.axisY.labelInterpolationFnc, - Chartist.getWidth + 'width' ); } diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index ac89789f..85853aad 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.2.1 +/* Chartist.js 0.2.2 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 4b7148bf..ab5605e7 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.2.1 +/* Chartist.js 0.2.2 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.1.14",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getHeight=function(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight},c.getWidth=function(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b||"100%",height:d||"100%"}).removeAllClasses().addClass(e),f.empty()):(f=c.Svg("svg").attr({width:b||"100%",height:d||"100%"}).addClass(e),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return c.getHeight(a._node)-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(t,a);return"svg"===a&&i.setAttributeNS(u,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",v);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}var t="http://www.w3.org/2000/svg",u="http://www.w3.org/2000/xmlns/",v="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,c.getHeight)),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,c.getWidth));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===d.series.filter(function(a){return 0!==a}).length,o=0;o=r-j?"0":"1",v=["M",t.x,t.y,"A",e,e,0,u,0,s.x,s.y];a.donut===!1&&v.push("L",l.x,l.y);var w=i[o].elem("path",{d:v.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(w.attr({value:k[o]},c.xmlNs.uri),a.donut===!0&&w.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[o],totalDataSum:h,index:o,group:i[o],element:w,center:l,radius:e,startAngle:j,endAngle:r}),a.showLabel){var x=c.polarToCartesian(l.x,l.y,f,j+(r-j)/2),y=a.labelInterpolationFnc(d.labels?d.labels[o]:k[o],o),z=i[o].elem("text",{dx:x.x,dy:x.y,"text-anchor":g(l,x,a.labelDirection)},a.classNames.label).text(""+y);q.emit("draw",{type:"label",index:o,group:i[o],element:z,text:""+y,x:x.x,y:x.y})}j=r}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.clear()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.2.2",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return a.height()-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(v,a);return"svg"===a&&i.setAttributeNS(w,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",x);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}function t(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight}function u(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth}var v="http://www.w3.org/2000/svg",w="http://www.w3.org/2000/xmlns/",x="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)},height:function(){return t(this._node)},width:function(){return u(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,"height")),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,"width"));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===d.series.filter(function(a){return 0!==a}).length,o=0;o=r-j?"0":"1",v=["M",t.x,t.y,"A",e,e,0,u,0,s.x,s.y];a.donut===!1&&v.push("L",l.x,l.y);var w=i[o].elem("path",{d:v.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(w.attr({value:k[o]},c.xmlNs.uri),a.donut===!0&&w.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[o],totalDataSum:h,index:o,group:i[o],element:w,center:l,radius:e,startAngle:j,endAngle:r}),a.showLabel){var x=c.polarToCartesian(l.x,l.y,f,j+(r-j)/2),y=a.labelInterpolationFnc(d.labels?d.labels[o]:k[o],o),z=i[o].elem("text",{dx:x.x,dy:x.y,"text-anchor":g(l,x,a.labelDirection)},a.classNames.label).text(""+y);q.emit("draw",{type:"label",index:o,group:i[o],element:z,text:""+y,x:x.x,y:x.y})}j=r}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.clear()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 23027d43..9ecf51b4 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getHeight","svgElement","clientHeight","Math","round","getBBox","height","parentNode","getWidth","clientWidth","width","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":25484,"pos":25470,"col":12,"line":659,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":25484,"pos":25470,"col":12,"line":659,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaPathElements","slice","areaBaseProjected","areaBase","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","clear","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","style","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.1.14';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its height\n * @return {Number} The elements height in pixels\n */\n Chartist.getHeight = function (svgElement) {\n return svgElement.clientHeight || Math.round(svgElement.getBBox().height) || svgElement.parentNode.clientHeight;\n };\n\n //TODO: move into Chartist.Svg\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @param {Node} svgElement The svg element from which we want to retrieve its width\n * @return {Number} The elements width in pixels\n */\n Chartist.getWidth = function (svgElement) {\n return svgElement.clientWidth || Math.round(svgElement.getBBox().width) || svgElement.parentNode.clientWidth;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width || '100%',\n height: height || '100%'\n }).removeAllClasses().addClass(className);\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = Chartist.Svg('svg').attr({\n width: width || '100%',\n height: height || '100%'\n }).addClass(className);\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 Chartist.getHeight(svg._node) - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {Function} offsetFnc Function to find greatest value of either the width or the height of the label, depending on the context\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, offsetFnc(label._node));\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || Chartist.getHeight(svg._node)) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) ||Chartist.getWidth(svg._node)) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + Chartist.getHeight(labelElement._node) + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [options.areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n Chartist.getHeight\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n Chartist.getWidth\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","slice","areaBaseProjected","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","clear","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.2\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.2.2';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 svg.height() - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, label[offsetFnc]());\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index 233fed8a..b35d73bf 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.2.1", + "version": "0.2.2", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 7dcc5ac6..43932ab5 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = {}; -Chartist.version = '0.1.14'; +Chartist.version = '0.2.2'; (function (window, document, Chartist) { 'use strict'; From ef3d3826dd4248fc73132226a73060d8f5e7aa7f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 15 Oct 2014 20:12:18 +0200 Subject: [PATCH 030/593] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 12f64c49..dc14be16 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ *Checkout this lightening talk that gives you an overview of Chartist in 5 minutes https://www.youtube.com/watch?v=WdYzPhOB_c8* +*Guest talk of the Chartist.js Guy at the Treehouse Show https://www.youtube.com/watch?v=h9oH0iDaZDQ&t=2m40s* + Chartist.js is a simple responsive charting library built with SVG. There are hundreds of nice charting libraries already out there, but they are either: From ab19ed0a985695d2587c0a03378634cc8c6eb250 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 16 Oct 2014 22:58:44 +0200 Subject: [PATCH 031/593] Fixed bug with detach function not calling the refactored removeMediaQueryListeners method on the optionsProvider, fixes #69 --- source/scripts/chartist.bar.js | 2 +- source/scripts/chartist.pie.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index fd7edce7..c0b125f0 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -266,7 +266,7 @@ */ function detach() { window.removeEventListener('resize', update); - optionsProvider.clear(); + optionsProvider.removeMediaQueryListeners(); } /** diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index c3a89391..a83998e9 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -296,7 +296,7 @@ */ function detach() { window.removeEventListener('resize', update); - optionsProvider.clear(); + optionsProvider.removeMediaQueryListeners(); } /** From c4b307c6c5e4a2a1cf5db8858ec6b75bfb0991aa Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 16 Oct 2014 23:12:07 +0200 Subject: [PATCH 032/593] Updated version to 0.2.3 --- bower.json | 2 +- libdist/chartist.js | 8 ++++---- libdist/chartist.min.css | 2 +- libdist/chartist.min.js | 4 ++-- libdist/chartist.min.map | 2 +- package.json | 2 +- source/scripts/chartist.core.js | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bower.json b/bower.json index 4d49a688..0125a548 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.2.2", + "version": "0.2.3", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index 3c15a2b8..79e29cdd 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.2.2 + /* Chartist.js 0.2.3 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -21,7 +21,7 @@ * @module Chartist.Core */ var Chartist = {}; - Chartist.version = '0.2.2'; + Chartist.version = '0.2.3'; (function (window, document, Chartist) { 'use strict'; @@ -1757,7 +1757,7 @@ */ function detach() { window.removeEventListener('resize', update); - optionsProvider.clear(); + optionsProvider.removeMediaQueryListeners(); } /** @@ -2107,7 +2107,7 @@ */ function detach() { window.removeEventListener('resize', update); - optionsProvider.clear(); + optionsProvider.removeMediaQueryListeners(); } /** diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index 85853aad..be412b9a 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.2.2 +/* Chartist.js 0.2.3 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index ab5605e7..4fe9bcbf 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.2.2 +/* Chartist.js 0.2.3 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.2.2",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return a.height()-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(v,a);return"svg"===a&&i.setAttributeNS(w,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",x);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}function t(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight}function u(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth}var v="http://www.w3.org/2000/svg",w="http://www.w3.org/2000/xmlns/",x="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)},height:function(){return t(this._node)},width:function(){return u(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,"height")),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,"width"));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===d.series.filter(function(a){return 0!==a}).length,o=0;o=r-j?"0":"1",v=["M",t.x,t.y,"A",e,e,0,u,0,s.x,s.y];a.donut===!1&&v.push("L",l.x,l.y);var w=i[o].elem("path",{d:v.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(w.attr({value:k[o]},c.xmlNs.uri),a.donut===!0&&w.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[o],totalDataSum:h,index:o,group:i[o],element:w,center:l,radius:e,startAngle:j,endAngle:r}),a.showLabel){var x=c.polarToCartesian(l.x,l.y,f,j+(r-j)/2),y=a.labelInterpolationFnc(d.labels?d.labels[o]:k[o],o),z=i[o].elem("text",{dx:x.x,dy:x.y,"text-anchor":g(l,x,a.labelDirection)},a.classNames.label).text(""+y);q.emit("draw",{type:"label",index:o,group:i[o],element:z,text:""+y,x:x.x,y:x.y})}j=r}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.clear()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.2.3",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return a.height()-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(v,a);return"svg"===a&&i.setAttributeNS(w,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",x);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}function t(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight}function u(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth}var v="http://www.w3.org/2000/svg",w="http://www.w3.org/2000/xmlns/",x="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)},height:function(){return t(this._node)},width:function(){return u(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,"height")),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,"width"));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===d.series.filter(function(a){return 0!==a}).length,o=0;o=r-j?"0":"1",v=["M",t.x,t.y,"A",e,e,0,u,0,s.x,s.y];a.donut===!1&&v.push("L",l.x,l.y);var w=i[o].elem("path",{d:v.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(w.attr({value:k[o]},c.xmlNs.uri),a.donut===!0&&w.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[o],totalDataSum:h,index:o,group:i[o],element:w,center:l,radius:e,startAngle:j,endAngle:r}),a.showLabel){var x=c.polarToCartesian(l.x,l.y,f,j+(r-j)/2),y=a.labelInterpolationFnc(d.labels?d.labels[o]:k[o],o),z=i[o].elem("text",{dx:x.x,dy:x.y,"text-anchor":g(l,x,a.labelDirection)},a.classNames.label).text(""+y);q.emit("draw",{type:"label",index:o,group:i[o],element:z,text:""+y,x:x.x,y:x.y})}j=r}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.removeMediaQueryListeners()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 9ecf51b4..da920476 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","slice","areaBaseProjected","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","clear","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.2\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.2.2';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 svg.height() - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, label[offsetFnc]());\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.clear();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","slice","areaBaseProjected","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.3\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.2.3';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 svg.height() - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, label[offsetFnc]());\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index b35d73bf..b97170d3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.2.2", + "version": "0.2.3", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 43932ab5..1b9a6f35 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = {}; -Chartist.version = '0.2.2'; +Chartist.version = '0.2.3'; (function (window, document, Chartist) { 'use strict'; From 07b047647dfdaf3918bef100a5047e4d0e83da0e Mon Sep 17 00:00:00 2001 From: Will Date: Fri, 17 Oct 2014 11:33:56 -0400 Subject: [PATCH 033/593] Move optionsProvider into setTimeout --- source/scripts/chartist.bar.js | 6 +++--- source/scripts/chartist.line.js | 6 +++--- source/scripts/chartist.pie.js | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index c0b125f0..7d8f3efb 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -295,12 +295,12 @@ window.addEventListener('resize', update); - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. setTimeout(function() { + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); createChart(optionsProvider.currentOptions); }, 0); diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index d9abbb61..2cf4f570 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -379,12 +379,12 @@ window.addEventListener('resize', update); - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. setTimeout(function() { + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); createChart(optionsProvider.currentOptions); }, 0); diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index a83998e9..be349b7a 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -325,12 +325,12 @@ window.addEventListener('resize', update); - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. setTimeout(function() { + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); createChart(optionsProvider.currentOptions); }, 0); @@ -347,4 +347,4 @@ return api; }; -}(window, document, Chartist)); \ No newline at end of file +}(window, document, Chartist)); From 46f4d309b17f4aac42b8050cd16ee941ddb9288d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:20:12 +0200 Subject: [PATCH 034/593] Ignoring possible missuse of this keyword as we will have a revealing module pattern style of writing classes --- .jshintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.jshintrc b/.jshintrc index 373fed11..643740a3 100644 --- a/.jshintrc +++ b/.jshintrc @@ -16,6 +16,7 @@ "undef": true, "unused": true, "strict": true, + "validthis": true, "trailing": true, "smarttabs": true, "globals": { From 3451baf6856f060c33356ba16bfab4dc78e27a46 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:21:51 +0200 Subject: [PATCH 035/593] Added chartist type utility module that helps to create prototype based objects --- source/scripts/chartist.class.js | 217 +++++++++++++++++++++++++++++++ source/scripts/chartist.core.js | 1 + 2 files changed, 218 insertions(+) create mode 100644 source/scripts/chartist.class.js diff --git a/source/scripts/chartist.class.js b/source/scripts/chartist.class.js new file mode 100644 index 00000000..42171e66 --- /dev/null +++ b/source/scripts/chartist.class.js @@ -0,0 +1,217 @@ +/** + * This module provides some basic prototype inheritance utilities. + * + * @module Chartist.Class + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + function listToArray(list) { + var arr = []; + if (list.length) { + for (var i = 0; i < list.length; i++) { + arr.push(list[i]); + } + } + return arr; + } + + /** + * Method to extend from current prototype. + * + * @memberof Chartist.Class + * @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. + * @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. + * @returns {Function} Constructor function of the new class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + */ + function extend(properties, superProtoOverride) { + var superProto = superProtoOverride || this.prototype || Chartist.Class; + var proto = Object.create(superProto); + + Chartist.Class.cloneDefinitions(proto, properties); + + var constr = function() { + var fn = proto.constructor || function () {}, + instance; + + // If this is linked to the Chartist namespace the constructor was not called with new + // To provide a fallback we will instantiate here and return the instance + instance = this === Chartist ? Object.create(proto) : this; + fn.apply(instance, Array.prototype.slice.call(arguments, 0)); + + // If this constructor was not called with new we need to return the instance + // This will not harm when the constructor has been called with new as the returned value is ignored + return instance; + }; + + constr.prototype = proto; + constr.super = superProto; + constr.extend = this.extend; + + return constr; + } + + /** + * Creates a mixin from multiple super prototypes. + * + * @memberof Chartist.Class + * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. + * @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. + * @returns {Function} Constructor function of the newly created mixin class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * + * var KCal = Class.extend({ + * sugar: 0, + * + * constructor: function(sugar) { + * this.sugar = sugar; + * }, + * + * get kcal() { + * return [this.sugar * 4, 'kcal'].join(''); + * } + * }); + * + * var Nameable = Class.extend({ + * name: undefined, + * + * constructor: function(name) { + * this.name = name; + * } + * }); + * + * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { + * constructor: function(name, length, sugar) { + * Nameable.prototype.constructor.call(this, name); + * Banana.prototype.constructor.call(this, length, sugar); + * }, + * + * toString: function() { + * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); + * } + * }); + * + * + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); + * console.log(superBanana.toString()); + * + */ + function mix(mixProtoArr, properties) { + if(this !== Chartist.Class) { + throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); + } + + // Make sure our mixin prototypes are the class objects and not the constructors + var superPrototypes = [{}] + .concat(mixProtoArr) + .map(function (prototype) { + return prototype instanceof Function ? prototype.prototype : prototype; + }); + + var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); + // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype + delete mixedSuperProto.constructor; + return this.extend(properties, mixedSuperProto); + } + + // Variable argument list clones args > 0 into args[0] and retruns modified args[0] + function cloneDefinitions() { + var args = listToArray(arguments); + var target = args[0]; + + args.splice(1, args.length - 1).forEach(function (source) { + Object.getOwnPropertyNames(source).forEach(function (propName) { + // If this property already exist in target we delete it first + delete target[propName]; + // Define the property with the descriptor from source + Object.defineProperty(target, propName, + Object.getOwnPropertyDescriptor(source, propName)); + }); + }); + + return target; + } + + Chartist.Class = { + extend: extend, + mix: mix, + cloneDefinitions: cloneDefinitions + }; + +}(window, document, Chartist)); \ No newline at end of file diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 1b9a6f35..c273b460 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -32,6 +32,7 @@ Chartist.version = '0.2.3'; return String.fromCharCode(97 + n % 26); }; + // TODO: Make it possible to call extend with var args /** * Simple recursive object extend * From 99e4ddbdd2c458c6b20e31ea35d811acc63d2f0e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:22:27 +0200 Subject: [PATCH 036/593] Added base chart class that serves as base for all chart types --- source/scripts/chartist.base.js | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 source/scripts/chartist.base.js diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js new file mode 100644 index 00000000..0cd30c60 --- /dev/null +++ b/source/scripts/chartist.base.js @@ -0,0 +1,102 @@ +/** + * Base for all chart classes. + * + * @module Chartist.Base + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container + /** + * Updates the chart which currently does a full reconstruction of the SVG DOM + * + * @memberof Chartist.Line + */ + function update() { + this.createChart(this.optionsProvider.currentOptions); + } + + /** + * 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. + * + * @memberof Chartist.Line + */ + function detach() { + window.removeEventListener('resize', this.update); + this.optionsProvider.removeMediaQueryListeners(); + } + + /** + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. + * + * @memberof Chartist.Line + * @param {String} event Name of the event. Check the examples for supported events. + * @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. + */ + function on(event, handler) { + this.eventEmitter.addEventHandler(event, handler); + } + + /** + * 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. + * + * @memberof Chartist.Line + * @param {String} event Name of the event for which a handler should be removed + * @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. + */ + function off(event, handler) { + this.eventEmitter.removeEventHandler(event, handler); + } + + /** + * Constructor of chart base class. + * + * @param query + * @param data + * @param options + * @param responsiveOptions + * @constructor + */ + function Base(query, data, options, responsiveOptions) { + this.container = Chartist.querySelector(query); + this.data = data; + this.options = options; + this.responsiveOptions = responsiveOptions; + this.eventEmitter = Chartist.EventEmitter(); + + window.addEventListener('resize', this.update.bind(this)); + + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + // TODO: Remove default options parameter from optionsProvider + this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter); + this.createChart(this.optionsProvider.currentOptions); + }.bind(this), 0); + } + + // Creating the chart base class + Chartist.Base = Chartist.Class.extend({ + constructor: Base, + optionsProvider: undefined, + container: undefined, + svg: undefined, + eventEmitter: undefined, + createChart: function() { + throw new Error('Base chart type can\'t be instantiated!'); + }, + update: update, + detach: detach, + on: on, + off: off + }); + +}(window, document, Chartist)); \ No newline at end of file From 5c30eb155dbbdb893f08690089f575b9bf021b88 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:23:01 +0200 Subject: [PATCH 037/593] Added new class and base files to the build process and to the main layout for the doc site --- Gruntfile.js | 13 ++++++++++++- source/site/layouts/default.hbs | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 6c60cb73..b479eb75 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -342,6 +342,8 @@ module.exports = function (grunt) { src: [ 'source/scripts/chartist.core.js', 'source/scripts/chartist.event.js', + 'source/scripts/chartist.class.js', + 'source/scripts/chartist.base.js', 'source/scripts/chartist.svg.js', 'source/scripts/chartist.line.js', 'source/scripts/chartist.bar.js', @@ -390,7 +392,16 @@ module.exports = function (grunt) { banner: pkg.config.banner }, files: { - 'libdist/chartist.js': ['source/scripts/chartist.core.js', 'source/scripts/chartist.event.js', 'source/scripts/chartist.svg.js', 'source/scripts/chartist.line.js', 'source/scripts/chartist.bar.js', 'source/scripts/chartist.pie.js'] + 'libdist/chartist.js': [ + 'source/scripts/chartist.core.js', + 'source/scripts/chartist.event.js', + 'source/scripts/chartist.class.js', + 'source/scripts/chartist.base.js', + 'source/scripts/chartist.svg.js', + 'source/scripts/chartist.line.js', + 'source/scripts/chartist.bar.js', + 'source/scripts/chartist.pie.js' + ] } } }, diff --git a/source/site/layouts/default.hbs b/source/site/layouts/default.hbs index 179d147f..b83e88e8 100644 --- a/source/site/layouts/default.hbs +++ b/source/site/layouts/default.hbs @@ -54,6 +54,8 @@ + + From ec22c7d1d65bd9aa66c3e23ae02ccb5716bbc57d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:24:02 +0200 Subject: [PATCH 038/593] Refactored chart types to prototype based style, fixes #74 --- source/scripts/chartist.bar.js | 359 ++++++++++--------------- source/scripts/chartist.line.js | 459 ++++++++++++++------------------ source/scripts/chartist.pie.js | 453 ++++++++++++++----------------- 3 files changed, 538 insertions(+), 733 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 7d8f3efb..51e3cdec 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -7,6 +7,140 @@ (function(window, document, Chartist){ 'use strict'; + var defaultOptions = { + axisX: { + offset: 10, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 15, + showLabel: true, + showGrid: true, + labelAlign: 'right', + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 40 + }, + width: undefined, + height: undefined, + high: undefined, + low: undefined, + chartPadding: 5, + seriesBarDistance: 15, + classNames: { + chart: 'ct-chart-bar', + label: 'ct-label', + series: 'ct-series', + bar: 'ct-bar', + thin: 'ct-thin', + thick: 'ct-thick', + grid: 'ct-grid', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var xAxisOffset, + yAxisOffset, + seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg element + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); + + xAxisOffset = options.axisX.offset; + if (options.axisX.showLabel) { + xAxisOffset += Chartist.calculateLabelOffset( + this.svg, + this.data.labels, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisX.labelInterpolationFnc, + 'height' + ); + } + + yAxisOffset = options.axisY.offset; + if (options.axisY.showLabel) { + yAxisOffset += Chartist.calculateLabelOffset( + this.svg, + bounds.values, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisY.labelInterpolationFnc, + 'width' + ); + } + + var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + // Start drawing + var labels = this.svg.elem('g'), + grid = this.svg.elem('g'), + // Projected 0 point + zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. + var biPol = i - (this.data.series.length - 1) / 2, + // Half of the period with between vertical grid lines used to position bars + periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; + + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + for(var j = 0; j < normalizedData[i].length; j++) { + var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), + bar; + + // Offset to center bar between grid lines and using bi-polar offset for multiple series + // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors + p.x += periodHalfWidth + (biPol * options.seriesBarDistance); + + bar = seriesGroups[i].elem('line', { + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }, options.classNames.bar).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'bar', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: bar, + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }); + } + } + } + /** * This method creates a new bar chart and returns API object that you can use for later changes. * @@ -104,217 +238,18 @@ * }); * */ - Chartist.Bar = function (query, data, options, responsiveOptions) { - - var defaultOptions = { - axisX: { - offset: 10, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 15, - showLabel: true, - showGrid: true, - labelAlign: 'right', - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 40 - }, - width: undefined, - height: undefined, - high: undefined, - low: undefined, - chartPadding: 5, - seriesBarDistance: 15, - classNames: { - chart: 'ct-chart-bar', - label: 'ct-label', - series: 'ct-series', - bar: 'ct-bar', - thin: 'ct-thin', - thick: 'ct-thick', - grid: 'ct-grid', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }, - optionsProvider, - container = Chartist.querySelector(query), - svg, - eventEmitter = Chartist.EventEmitter(); - - function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length); - - // Create new svg element - svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart); - - // initialize bounds - bounds = Chartist.getBounds(svg, normalizedData, options, 0); - - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - svg, - data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } - - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } - - var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset); - // Start drawing - var labels = svg.elem('g'), - grid = svg.elem('g'), - // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - - Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); - - // Draw the series - // initialize series groups - for (var i = 0; i < data.series.length; i++) { - // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = i - (data.series.length - 1) / 2, - // Half of the period with between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; - - seriesGroups[i] = svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), - bar; - - // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors - p.x += periodHalfWidth + (biPol * options.seriesBarDistance); - - bar = seriesGroups[i].elem('line', { - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }, options.classNames.bar).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); - - eventEmitter.emit('draw', { - type: 'bar', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: bar, - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }); - } - } - } - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Bar - */ - function update() { - createChart(optionsProvider.currentOptions); - } - - /** - * 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. - * - * @memberof Chartist.Bar - */ - function detach() { - window.removeEventListener('resize', update); - optionsProvider.removeMediaQueryListeners(); - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Bar - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - eventEmitter.addEventHandler(event, handler); - } - - /** - * 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. - * - * @memberof Chartist.Bar - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - eventEmitter.removeEventHandler(event, handler); - } - - // Initialization of the chart - - window.addEventListener('resize', update); - - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); - createChart(optionsProvider.currentOptions); - }, 0); - - // Public members of the module (revealing module pattern style) - var api = { - version: Chartist.version, - update: update, - on: on, - off: off, - detach: detach - }; - - container.chartist = api; - return api; - }; + function Bar(query, data, options, responsiveOptions) { + Chartist.Bar.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } + + // Creating bar chart type in Chartist namespace + Chartist.Bar = Chartist.Base.extend({ + constructor: Bar, + createChart: createChart + }); }(window, document, Chartist)); diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 2cf4f570..9fe26368 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -9,8 +9,191 @@ (function(window, document, Chartist){ 'use strict'; + var defaultOptions = { + axisX: { + offset: 10, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 15, + showLabel: true, + showGrid: true, + labelAlign: 'right', + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 30 + }, + width: undefined, + height: undefined, + showLine: true, + showPoint: true, + showArea: false, + areaBase: 0, + lineSmooth: true, + low: undefined, + high: undefined, + chartPadding: 5, + classNames: { + chart: 'ct-chart-line', + label: 'ct-label', + series: 'ct-series', + line: 'ct-line', + point: 'ct-point', + area: 'ct-area', + grid: 'ct-grid', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var xAxisOffset, + yAxisOffset, + seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg object + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options); + + xAxisOffset = options.axisX.offset; + if (options.axisX.showLabel) { + xAxisOffset += Chartist.calculateLabelOffset( + this.svg, + this.data.labels, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisX.labelInterpolationFnc, + 'height' + ); + } + + yAxisOffset = options.axisY.offset; + if (options.axisY.showLabel) { + yAxisOffset += Chartist.calculateLabelOffset( + this.svg, + bounds.values, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisY.labelInterpolationFnc, + 'width' + ); + } + + var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + // Start drawing + var labels = this.svg.elem('g'), + grid = this.svg.elem('g'); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var p, + pathCoordinates = [], + point; + + for (var j = 0; j < normalizedData[i].length; j++) { + p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); + pathCoordinates.push(p.x, p.y); + + //If we should show points we need to create them now to avoid secondary loop + // Small offset for Firefox to render squares correctly + if (options.showPoint) { + point = seriesGroups[i].elem('line', { + x1: p.x, + y1: p.y, + x2: p.x + 0.01, + y2: p.y + }, options.classNames.point).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'point', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: point, + x: p.x, + y: p.y + }); + } + } + + // TODO: Nicer handling of conditions, maybe composition? + if (options.showLine || options.showArea) { + // TODO: We should add a path API in the SVG library for easier path creation + var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; + + // If smoothed path and path has more than two points then use catmull rom to bezier algorithm + if (options.lineSmooth && pathCoordinates.length > 4) { + + var cr = Chartist.catmullRom2bezier(pathCoordinates); + for(var k = 0; k < cr.length; k++) { + pathElements.push('C' + cr[k].join()); + } + } else { + for(var l = 3; l < pathCoordinates.length; l += 2) { + pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); + } + } + + if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); + + // If we need to draw area shapes we just make a copy of our pathElements SVG path array + var areaPathElements = pathElements.slice(); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); + // And splice our new area path array to add the missing path elements to close the area shape + areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); + areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; + areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + + // Create the new path for the area shape with the area class from the options + seriesGroups[i].elem('path', { + d: areaPathElements.join('') + }, options.classNames.area, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } + + if(options.showLine) { + seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } + } + } + } + /** - * This method creates a new line chart and returns API object that you can use for later changes. + * This method creates a new line chart. * * @memberof Chartist.Line * @param {String|Node} query A selector query string or directly a DOM element @@ -139,266 +322,18 @@ * Chartist.Line('.ct-chart', data, null, responsiveOptions); * */ - Chartist.Line = function (query, data, options, responsiveOptions) { - - var defaultOptions = { - axisX: { - offset: 10, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 15, - showLabel: true, - showGrid: true, - labelAlign: 'right', - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 30 - }, - width: undefined, - height: undefined, - showLine: true, - showPoint: true, - showArea: false, - areaBase: 0, - lineSmooth: true, - low: undefined, - high: undefined, - chartPadding: 5, - classNames: { - chart: 'ct-chart-line', - label: 'ct-label', - series: 'ct-series', - line: 'ct-line', - point: 'ct-point', - area: 'ct-area', - grid: 'ct-grid', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }, - optionsProvider, - container = Chartist.querySelector(query), - svg, - eventEmitter = Chartist.EventEmitter(); - - function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length); - - // Create new svg object - svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart); - - // initialize bounds - bounds = Chartist.getBounds(svg, normalizedData, options); - - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - svg, - data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } - - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } - - var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset); - // Start drawing - var labels = svg.elem('g'), - grid = svg.elem('g'); - - Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); - - // Draw the series - // initialize series groups - for (var i = 0; i < data.series.length; i++) { - seriesGroups[i] = svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var p, - pathCoordinates = [], - point; - - for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); - pathCoordinates.push(p.x, p.y); - - //If we should show points we need to create them now to avoid secondary loop - // Small offset for Firefox to render squares correctly - if (options.showPoint) { - point = seriesGroups[i].elem('line', { - x1: p.x, - y1: p.y, - x2: p.x + 0.01, - y2: p.y - }, options.classNames.point).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); - - eventEmitter.emit('draw', { - type: 'point', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: point, - x: p.x, - y: p.y - }); - } - } - - // TODO: Nicer handling of conditions, maybe composition? - if (options.showLine || options.showArea) { - // TODO: We should add a path API in the SVG library for easier path creation - var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; - - // If smoothed path and path has more than two points then use catmull rom to bezier algorithm - if (options.lineSmooth && pathCoordinates.length > 4) { - - var cr = Chartist.catmullRom2bezier(pathCoordinates); - for(var k = 0; k < cr.length; k++) { - pathElements.push('C' + cr[k].join()); - } - } else { - for(var l = 3; l < pathCoordinates.length; l += 2) { - pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); - } - } - - if(options.showArea) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); - - // If we need to draw area shapes we just make a copy of our pathElements SVG path array - var areaPathElements = pathElements.slice(); - - // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); - // And splice our new area path array to add the missing path elements to close the area shape - areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); - areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; - areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); - - // Create the new path for the area shape with the area class from the options - seriesGroups[i].elem('path', { - d: areaPathElements.join('') - }, options.classNames.area, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - } - - if(options.showLine) { - seriesGroups[i].elem('path', { - d: pathElements.join('') - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - } - } - } - } - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Line - */ - function update() { - createChart(optionsProvider.currentOptions); - } - - /** - * 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. - * - * @memberof Chartist.Line - */ - function detach() { - window.removeEventListener('resize', update); - optionsProvider.removeMediaQueryListeners(); - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Line - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - eventEmitter.addEventHandler(event, handler); - } - - /** - * 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. - * - * @memberof Chartist.Line - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - eventEmitter.removeEventHandler(event, handler); - } - - // Initialization of the chart - - window.addEventListener('resize', update); - - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); - createChart(optionsProvider.currentOptions); - }, 0); - - // Public members of the module (revealing module pattern style) - var api = { - version: Chartist.version, - update: update, - on: on, - off: off, - detach: detach - }; - - container.chartist = api; - return api; - }; + function Line(query, data, options, responsiveOptions) { + Chartist.Line.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } + + // Creating line chart type in Chartist namespace + Chartist.Line = Chartist.Base.extend({ + constructor: Line, + createChart: createChart + }); }(window, document, Chartist)); diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index be349b7a..9c2af9b9 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -7,6 +7,186 @@ (function(window, document, Chartist) { 'use strict'; + var defaultOptions = { + width: undefined, + height: undefined, + chartPadding: 5, + classNames: { + chart: 'ct-chart-pie', + series: 'ct-series', + slice: 'ct-slice', + donut: 'ct-donut', + label: 'ct-label' + }, + startAngle: 0, + total: undefined, + donut: false, + donutWidth: 60, + showLabel: true, + labelOffset: 0, + labelInterpolationFnc: Chartist.noop, + labelOverflow: false, + labelDirection: 'neutral' + }; + + function determineAnchorPosition(center, label, direction) { + var toTheRight = label.x > center.x; + + if(toTheRight && direction === 'explode' || + !toTheRight && direction === 'implode') { + return 'start'; + } else if(toTheRight && direction === 'implode' || + !toTheRight && direction === 'explode') { + return 'end'; + } else { + return 'middle'; + } + } + + function createChart(options) { + var seriesGroups = [], + chartRect, + radius, + labelRadius, + totalDataSum, + startAngle = options.startAngle, + dataArray = Chartist.getDataArray(this.data); + + // Create SVG.js draw + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + // Calculate charting rect + chartRect = Chartist.createChartRect(this.svg, options, 0, 0); + // Get biggest circle radius possible within chartRect + radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + // Calculate total of all series to get reference value or use total reference from optional options + totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { + return previousValue + currentValue; + }, 0); + + // 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 ? options.donutWidth / 2 : 0; + + // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius + // see https://github.com/gionkunz/chartist-js/issues/21 + labelRadius = options.donut ? radius : radius / 2; + // Add the offset to the labelRadius where a negative offset means closed to the center of the chart + labelRadius += options.labelOffset; + + // Calculate end angle based on total sum and current data value and offset with padding + var center = { + x: chartRect.x1 + chartRect.width() / 2, + y: chartRect.y2 + chartRect.height() / 2 + }; + + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = this.data.series.filter(function(val) { + return val !== 0; + }).length === 1; + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g', null, null, true); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle + // with Z and use 359.99 degrees + if(endAngle - startAngle === 360) { + endAngle -= 0.01; + } + + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), + arcSweep = endAngle - startAngle <= 180 ? '0' : '1', + d = [ + // Start at the end point from the cartesian coordinates + 'M', end.x, end.y, + // Draw arc + 'A', radius, radius, 0, arcSweep, 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 === false) { + d.push('L', center.x, center.y); + } + + // Create the SVG path + // If this is a donut chart we add the donut class, otherwise just a regular slice + var path = seriesGroups[i].elem('path', { + d: d.join(' ') + }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); + + // Adding the pie series value to the path + path.attr({ + 'value': dataArray[i] + }, Chartist.xmlNs.uri); + + // If this is a donut, we add the stroke-width as style attribute + if(options.donut === true) { + path.attr({ + 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' + }); + } + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'slice', + value: dataArray[i], + totalDataSum: totalDataSum, + index: i, + group: seriesGroups[i], + element: path, + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + + // If we need to show labels we need to add the label for this slice now + if(options.showLabel) { + // Position at the labelRadius distance from center and between start and end angle + var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), + interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + + var labelElement = seriesGroups[i].elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } + + // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // (except for last slice) + startAngle = endAngle; + } + } + /** * This method creates a new pie chart and returns an object that can be used to redraw the chart. * @@ -87,264 +267,19 @@ * labelDirection: 'explode' * }); */ - Chartist.Pie = function (query, data, options, responsiveOptions) { - - var defaultOptions = { - width: undefined, - height: undefined, - chartPadding: 5, - classNames: { - chart: 'ct-chart-pie', - series: 'ct-series', - slice: 'ct-slice', - donut: 'ct-donut', - label: 'ct-label' - }, - startAngle: 0, - total: undefined, - donut: false, - donutWidth: 60, - showLabel: true, - labelOffset: 0, - labelInterpolationFnc: Chartist.noop, - labelOverflow: false, - labelDirection: 'neutral' - }, - optionsProvider, - container = Chartist.querySelector(query), - svg, - eventEmitter = Chartist.EventEmitter(); - - function determineAnchorPosition(center, label, direction) { - var toTheRight = label.x > center.x; - - if(toTheRight && direction === 'explode' || - !toTheRight && direction === 'implode') { - return 'start'; - } else if(toTheRight && direction === 'implode' || - !toTheRight && direction === 'explode') { - return 'end'; - } else { - return 'middle'; - } - } - - function createChart(options) { - var seriesGroups = [], - chartRect, - radius, - labelRadius, - totalDataSum, - startAngle = options.startAngle, - dataArray = Chartist.getDataArray(data); - - // Create SVG.js draw - svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart); - // Calculate charting rect - chartRect = Chartist.createChartRect(svg, options, 0, 0); - // Get biggest circle radius possible within chartRect - radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); - // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { - return previousValue + currentValue; - }, 0); - - // 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 ? options.donutWidth / 2 : 0; - - // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius - // see https://github.com/gionkunz/chartist-js/issues/21 - labelRadius = options.donut ? radius : radius / 2; - // Add the offset to the labelRadius where a negative offset means closed to the center of the chart - labelRadius += options.labelOffset; - - // Calculate end angle based on total sum and current data value and offset with padding - var center = { - x: chartRect.x1 + chartRect.width() / 2, - y: chartRect.y2 + chartRect.height() / 2 - }; - - // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = data.series.filter(function(val) { - return val !== 0; - }).length === 1; - - // Draw the series - // initialize series groups - for (var i = 0; i < data.series.length; i++) { - seriesGroups[i] = svg.elem('g', null, null, true); - - // If the series is an object and contains a name we add a custom attribute - if(data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var endAngle = startAngle + dataArray[i] / totalDataSum * 360; - // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle - // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; - } - - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), - end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), - arcSweep = endAngle - startAngle <= 180 ? '0' : '1', - d = [ - // Start at the end point from the cartesian coordinates - 'M', end.x, end.y, - // Draw arc - 'A', radius, radius, 0, arcSweep, 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 === false) { - d.push('L', center.x, center.y); - } - - // Create the SVG path - // If this is a donut chart we add the donut class, otherwise just a regular slice - var path = seriesGroups[i].elem('path', { - d: d.join(' ') - }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); - - // Adding the pie series value to the path - path.attr({ - 'value': dataArray[i] - }, Chartist.xmlNs.uri); - - // If this is a donut, we add the stroke-width as style attribute - if(options.donut === true) { - path.attr({ - 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' - }); - } - - // Fire off draw event - eventEmitter.emit('draw', { - type: 'slice', - value: dataArray[i], - totalDataSum: totalDataSum, - index: i, - group: seriesGroups[i], - element: path, - center: center, - radius: radius, - startAngle: startAngle, - endAngle: endAngle - }); - - // If we need to show labels we need to add the label for this slice now - if(options.showLabel) { - // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i); - - var labelElement = seriesGroups[i].elem('text', { - dx: labelPosition.x, - dy: labelPosition.y, - 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) - }, options.classNames.label).text('' + interpolatedValue); - - // Fire off draw event - eventEmitter.emit('draw', { - type: 'label', - index: i, - group: seriesGroups[i], - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y - }); - } - - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues - // (except for last slice) - startAngle = endAngle; - } - } - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Pie - * - */ - function update() { - createChart(optionsProvider.currentOptions); - } - - /** - * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts. - * - * @memberof Chartist.Pie - */ - function detach() { - window.removeEventListener('resize', update); - optionsProvider.removeMediaQueryListeners(); - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Pie - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - eventEmitter.addEventHandler(event, handler); - } - - /** - * 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. - * - * @memberof Chartist.Pie - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - eventEmitter.removeEventHandler(event, handler); - } - - // Initialization of the chart - - window.addEventListener('resize', update); - - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); - createChart(optionsProvider.currentOptions); - }, 0); - - // Public members of the module (revealing module pattern style) - var api = { - version: Chartist.version, - update: update, - on: on, - off: off, - detach: detach - }; - - container.chartist = api; - return api; - }; + function Pie(query, data, options, responsiveOptions) { + Chartist.Pie.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } + + // Creating pie chart type in Chartist namespace + Chartist.Pie = Chartist.Base.extend({ + constructor: Pie, + createChart: createChart, + determineAnchorPosition: determineAnchorPosition + }); }(window, document, Chartist)); From 75c587ffdd8555800f95b10bb368bf3e684d3e4f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:47:18 +0200 Subject: [PATCH 039/593] Using new object instantiation for creating charts in example eval --- source/scripts/site/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/scripts/site/main.js b/source/scripts/site/main.js index 542a6ae3..875adac9 100644 --- a/source/scripts/site/main.js +++ b/source/scripts/site/main.js @@ -6,7 +6,7 @@ window.hljs.initHighlightingOnLoad(); function evalChartistCode(code, chartElement) { // Modify the code to use a proper selector using the ID of the example as well as return the Chartist object var modified = code.replace(/.*Chartist\s*\.\s*(.+)\(\s*['"](.+)['"]/, function(match, type) { - return ['var chart = Chartist.', type, '(chartElement'].join(''); + return ['var chart = new Chartist.', type, '(chartElement'].join(''); }) + '; return chart;'; // Remove any declaration of $chart as we are passing $chart to our function eval From d99bed0b199d0dd06190d4984a67e2997a3f139c Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:48:17 +0200 Subject: [PATCH 040/593] Updated inline examples in comments with new instantiation --- source/scripts/chartist.bar.js | 4 ++-- source/scripts/chartist.line.js | 4 ++-- source/scripts/chartist.pie.js | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 51e3cdec..71e53086 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -221,11 +221,11 @@ * }; * * // 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. - * Chartist.Bar('.ct-chart', data); + * new Chartist.Bar('.ct-chart', data); * * @example * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 - * Chartist.Bar('.ct-chart', { + * new Chartist.Bar('.ct-chart', { * labels: [1, 2, 3, 4, 5, 6, 7], * series: [ * [1, 3, 2, -5, -3, 1, -6], diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 9fe26368..23dffc3c 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -283,7 +283,7 @@ * }; * * // 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 - * Chartist.Line('.ct-chart', data, options); + * new Chartist.Line('.ct-chart', data, options); * * @example * // Create a line chart with responsive options @@ -319,7 +319,7 @@ * }] * ]; * - * Chartist.Line('.ct-chart', data, null, responsiveOptions); + * new Chartist.Line('.ct-chart', data, null, responsiveOptions); * */ function Line(query, data, options, responsiveOptions) { diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index 9c2af9b9..8477a5e8 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -234,13 +234,13 @@ * * @example * // Simple pie chart example with four series - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] * }); * * @example * // Drawing a donut chart - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] * }, { * donut: true @@ -248,7 +248,7 @@ * * @example * // Using donut, startAngle and total to draw a gauge chart - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [20, 10, 30, 40] * }, { * donut: true, @@ -259,7 +259,7 @@ * * @example * // Drawing a pie chart with padding and labels that are outside the pie - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [20, 10, 30, 40] * }, { * chartPadding: 30, From 459d9cc8354ecb163d276e74d93a418ebaca44ad Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:48:32 +0200 Subject: [PATCH 041/593] Updated documentation with new instantiation --- .../site/code-snippets/simple-start-aspect-ratio-chart.js | 8 ++++---- source/site/code-snippets/simple-start-fixed-chart.js | 8 ++++---- source/site/examples/behavior-with-jquery.js | 2 +- source/site/examples/bi-polar-bar-interpolated.js | 2 +- .../examples/example-bar-with-circle-modify-drawing.js | 2 +- source/site/examples/example-bipolar-line-area.js | 2 +- source/site/examples/example-gallery-four.js | 2 +- source/site/examples/example-gallery-one.js | 2 +- source/site/examples/example-gallery-three.js | 2 +- source/site/examples/example-gallery-two.js | 2 +- source/site/examples/example-line-area.js | 2 +- source/site/examples/example-line-modify-drawing.js | 2 +- source/site/examples/example-line-months-interpolation.js | 2 +- source/site/examples/example-line-simple-responsive.js | 2 +- source/site/examples/example-simple-bar.js | 2 +- source/site/examples/line-scatter-random.js | 2 +- source/site/examples/overlapping-bars.js | 2 +- source/site/examples/pie-with-custom-labels.js | 2 +- source/site/examples/simple-configuration-chart.js | 2 +- source/site/examples/simple-gauge-chart.js | 2 +- source/site/examples/simple-line-chart.js | 2 +- source/site/examples/simple-pie-chart.js | 2 +- 22 files changed, 28 insertions(+), 28 deletions(-) diff --git a/source/site/code-snippets/simple-start-aspect-ratio-chart.js b/source/site/code-snippets/simple-start-aspect-ratio-chart.js index 873ee0f5..96f838ea 100644 --- a/source/site/code-snippets/simple-start-aspect-ratio-chart.js +++ b/source/site/code-snippets/simple-start-aspect-ratio-chart.js @@ -7,7 +7,7 @@ var data = { ] }; -// 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 -Chartist.Line('.ct-chart', data); \ No newline at end of file +// Create a new line chart object where as first parameter we pass in a selector +// that is resolving to our chart container element. The Second parameter +// is the actual data object. +new Chartist.Line('.ct-chart', data); \ No newline at end of file diff --git a/source/site/code-snippets/simple-start-fixed-chart.js b/source/site/code-snippets/simple-start-fixed-chart.js index a7b3a25e..870130e7 100644 --- a/source/site/code-snippets/simple-start-fixed-chart.js +++ b/source/site/code-snippets/simple-start-fixed-chart.js @@ -14,7 +14,7 @@ var options = { height: 200 }; -// 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 -// Second parameter is the actual data object and as a third parameter we pass in our options -Chartist.Bar('.ct-chart', data, options); \ No newline at end of file +// Create a new line chart object where as first parameter we pass in a selector +// that is resolving to our chart container element. The Second parameter +// is the actual data object. As a third parameter we pass in our custom options. +new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file diff --git a/source/site/examples/behavior-with-jquery.js b/source/site/examples/behavior-with-jquery.js index 640d6c81..a79cafcb 100644 --- a/source/site/examples/behavior-with-jquery.js +++ b/source/site/examples/behavior-with-jquery.js @@ -1,4 +1,4 @@ -Chartist.Line('.ct-chart', { +new Chartist.Line('.ct-chart', { labels: ['1', '2', '3', '4', '5', '6'], series: [ { diff --git a/source/site/examples/bi-polar-bar-interpolated.js b/source/site/examples/bi-polar-bar-interpolated.js index 63452f08..e9c1da8e 100644 --- a/source/site/examples/bi-polar-bar-interpolated.js +++ b/source/site/examples/bi-polar-bar-interpolated.js @@ -15,4 +15,4 @@ var options = { } }; -Chartist.Bar('.ct-chart', data, options); \ No newline at end of file +new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file diff --git a/source/site/examples/example-bar-with-circle-modify-drawing.js b/source/site/examples/example-bar-with-circle-modify-drawing.js index c3fac2b0..ed304473 100644 --- a/source/site/examples/example-bar-with-circle-modify-drawing.js +++ b/source/site/examples/example-bar-with-circle-modify-drawing.js @@ -1,5 +1,5 @@ // Create a simple bi-polar bar chart -var chart = Chartist.Bar('.ct-chart', { +var chart = new Chartist.Bar('.ct-chart', { labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'], series: [ [1, 2, 4, 8, 6, -2, -1, -4, -6, -2] diff --git a/source/site/examples/example-bipolar-line-area.js b/source/site/examples/example-bipolar-line-area.js index 00c65822..03cd06fc 100644 --- a/source/site/examples/example-bipolar-line-area.js +++ b/source/site/examples/example-bipolar-line-area.js @@ -1,4 +1,4 @@ -Chartist.Line('.ct-chart', { +new Chartist.Line('.ct-chart', { labels: [1, 2, 3, 4, 5, 6, 7, 8], series: [ [1, 2, 3, 1, -2, 0, 1, 0], diff --git a/source/site/examples/example-gallery-four.js b/source/site/examples/example-gallery-four.js index 021af93d..f2a5f704 100644 --- a/source/site/examples/example-gallery-four.js +++ b/source/site/examples/example-gallery-four.js @@ -30,4 +30,4 @@ var responsiveOptions = [ ] ]; -Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/example-gallery-one.js b/source/site/examples/example-gallery-one.js index 6def30d9..ce527d00 100644 --- a/source/site/examples/example-gallery-one.js +++ b/source/site/examples/example-gallery-one.js @@ -17,4 +17,4 @@ var options = { } }; -Chartist.Line('.ct-chart', data, options); \ No newline at end of file +new Chartist.Line('.ct-chart', data, options); \ No newline at end of file diff --git a/source/site/examples/example-gallery-three.js b/source/site/examples/example-gallery-three.js index a84d07df..631f693f 100644 --- a/source/site/examples/example-gallery-three.js +++ b/source/site/examples/example-gallery-three.js @@ -37,4 +37,4 @@ var responsiveOptions = [ ] ]; -Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/example-gallery-two.js b/source/site/examples/example-gallery-two.js index 50ade374..1fe15ad7 100644 --- a/source/site/examples/example-gallery-two.js +++ b/source/site/examples/example-gallery-two.js @@ -16,4 +16,4 @@ var options = { } }; -Chartist.Bar('.ct-chart', data, options); \ No newline at end of file +new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file diff --git a/source/site/examples/example-line-area.js b/source/site/examples/example-line-area.js index 3b1ae568..ab86b923 100644 --- a/source/site/examples/example-line-area.js +++ b/source/site/examples/example-line-area.js @@ -1,4 +1,4 @@ -Chartist.Line('.ct-chart', { +new Chartist.Line('.ct-chart', { labels: [1, 2, 3, 4, 5, 6, 7, 8], series: [ [5, 9, 7, 8, 5, 3, 5, 4] diff --git a/source/site/examples/example-line-modify-drawing.js b/source/site/examples/example-line-modify-drawing.js index e61e1ada..d21fbb3b 100644 --- a/source/site/examples/example-line-modify-drawing.js +++ b/source/site/examples/example-line-modify-drawing.js @@ -1,4 +1,4 @@ -var chart = Chartist.Line('.ct-chart', { +var chart = new Chartist.Line('.ct-chart', { labels: [1, 2, 3, 4, 5], series: [ [12, 9, 7, 8, 5] diff --git a/source/site/examples/example-line-months-interpolation.js b/source/site/examples/example-line-months-interpolation.js index cb82c5e7..3c053bd6 100644 --- a/source/site/examples/example-line-months-interpolation.js +++ b/source/site/examples/example-line-months-interpolation.js @@ -25,4 +25,4 @@ var responsiveOptions = [ ] ]; -Chartist.Line('.ct-chart', data, null, responsiveOptions); \ No newline at end of file +new Chartist.Line('.ct-chart', data, null, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/example-line-simple-responsive.js b/source/site/examples/example-line-simple-responsive.js index a3ddef6a..62f98744 100644 --- a/source/site/examples/example-line-simple-responsive.js +++ b/source/site/examples/example-line-simple-responsive.js @@ -38,4 +38,4 @@ var responsiveOptions = [ ]; /* Initialize the chart with the above settings */ -Chartist.Line('#my-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Line('#my-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/example-simple-bar.js b/source/site/examples/example-simple-bar.js index 0e1c945a..f655562c 100644 --- a/source/site/examples/example-simple-bar.js +++ b/source/site/examples/example-simple-bar.js @@ -29,4 +29,4 @@ var responsiveOptions = [ }] ]; -Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/line-scatter-random.js b/source/site/examples/line-scatter-random.js index 2bf32446..593f37e9 100644 --- a/source/site/examples/line-scatter-random.js +++ b/source/site/examples/line-scatter-random.js @@ -33,4 +33,4 @@ var responsiveOptions = [ }] ]; -Chartist.Line('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Line('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/overlapping-bars.js b/source/site/examples/overlapping-bars.js index 38877e41..a8f16db1 100644 --- a/source/site/examples/overlapping-bars.js +++ b/source/site/examples/overlapping-bars.js @@ -21,4 +21,4 @@ var responsiveOptions = [ }] ]; -Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/pie-with-custom-labels.js b/source/site/examples/pie-with-custom-labels.js index 76502356..3ddf2c51 100644 --- a/source/site/examples/pie-with-custom-labels.js +++ b/source/site/examples/pie-with-custom-labels.js @@ -24,4 +24,4 @@ var responsiveOptions = [ }] ]; -Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/source/site/examples/simple-configuration-chart.js b/source/site/examples/simple-configuration-chart.js index 270e3133..7d3b8ced 100644 --- a/source/site/examples/simple-configuration-chart.js +++ b/source/site/examples/simple-configuration-chart.js @@ -35,4 +35,4 @@ var options = { }; // All you need to do is pass your configuration as third parameter to the chart function -Chartist.Line('.ct-chart', data, options); \ No newline at end of file +new Chartist.Line('.ct-chart', data, options); \ No newline at end of file diff --git a/source/site/examples/simple-gauge-chart.js b/source/site/examples/simple-gauge-chart.js index eb21ffcc..c7ffec9c 100644 --- a/source/site/examples/simple-gauge-chart.js +++ b/source/site/examples/simple-gauge-chart.js @@ -1,4 +1,4 @@ -Chartist.Pie('.ct-chart', { +new Chartist.Pie('.ct-chart', { series: [20, 10, 30, 40] }, { donut: true, diff --git a/source/site/examples/simple-line-chart.js b/source/site/examples/simple-line-chart.js index ae35681e..bffe7c3a 100644 --- a/source/site/examples/simple-line-chart.js +++ b/source/site/examples/simple-line-chart.js @@ -1,4 +1,4 @@ -Chartist.Line('.ct-chart', { +new Chartist.Line('.ct-chart', { labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], series: [ [12, 9, 7, 8, 5], diff --git a/source/site/examples/simple-pie-chart.js b/source/site/examples/simple-pie-chart.js index 6899fb24..3417aa1b 100644 --- a/source/site/examples/simple-pie-chart.js +++ b/source/site/examples/simple-pie-chart.js @@ -4,7 +4,7 @@ var data = { var sum = function(a, b) { return a + b }; -Chartist.Pie('.ct-chart', data, { +new Chartist.Pie('.ct-chart', data, { labelInterpolationFnc: function(value) { return Math.round(value / data.series.reduce(sum) * 100) + '%'; } From 32509c7cba6cfdbc63324b6fe6a9f2fba003ceff Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:51:28 +0200 Subject: [PATCH 042/593] Added version to base chart obtaining from Chartist namespace --- source/scripts/chartist.base.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js index 0cd30c60..f57a140f 100644 --- a/source/scripts/chartist.base.js +++ b/source/scripts/chartist.base.js @@ -96,7 +96,8 @@ update: update, detach: detach, on: on, - off: off + off: off, + version: Chartist.version }); }(window, document, Chartist)); \ No newline at end of file From c966fbd923c93377345aeed90cfeb0fe11df3c60 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:57:03 +0200 Subject: [PATCH 043/593] Updated to version 0.2.4 --- bower.json | 2 +- package.json | 2 +- source/scripts/chartist.core.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index 0125a548..e1165db1 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.2.3", + "version": "0.2.4", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/package.json b/package.json index b97170d3..dc6e1888 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.2.3", + "version": "0.2.4", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index c273b460..1410f268 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = {}; -Chartist.version = '0.2.3'; +Chartist.version = '0.2.4'; (function (window, document, Chartist) { 'use strict'; From a326908fc64c5abfc739d1980ed1bdf8b0ee5710 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 18 Oct 2014 14:58:25 +0200 Subject: [PATCH 044/593] Libdist of 0.2.4 --- libdist/chartist.js | 1585 ++++++++++++++++++++------------------ libdist/chartist.min.css | 2 +- libdist/chartist.min.js | 4 +- libdist/chartist.min.map | 2 +- 4 files changed, 859 insertions(+), 734 deletions(-) diff --git a/libdist/chartist.js b/libdist/chartist.js index 79e29cdd..9f951c7a 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.2.3 + /* Chartist.js 0.2.4 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -21,7 +21,7 @@ * @module Chartist.Core */ var Chartist = {}; - Chartist.version = '0.2.3'; + Chartist.version = '0.2.4'; (function (window, document, Chartist) { 'use strict'; @@ -49,6 +49,7 @@ return String.fromCharCode(97 + n % 26); }; + // TODO: Make it possible to call extend with var args /** * Simple recursive object extend * @@ -755,6 +756,324 @@ }; }; + }(window, document, Chartist));;/** + * This module provides some basic prototype inheritance utilities. + * + * @module Chartist.Class + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + function listToArray(list) { + var arr = []; + if (list.length) { + for (var i = 0; i < list.length; i++) { + arr.push(list[i]); + } + } + return arr; + } + + /** + * Method to extend from current prototype. + * + * @memberof Chartist.Class + * @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. + * @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. + * @returns {Function} Constructor function of the new class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + */ + function extend(properties, superProtoOverride) { + var superProto = superProtoOverride || this.prototype || Chartist.Class; + var proto = Object.create(superProto); + + Chartist.Class.cloneDefinitions(proto, properties); + + var constr = function() { + var fn = proto.constructor || function () {}, + instance; + + // If this is linked to the Chartist namespace the constructor was not called with new + // To provide a fallback we will instantiate here and return the instance + instance = this === Chartist ? Object.create(proto) : this; + fn.apply(instance, Array.prototype.slice.call(arguments, 0)); + + // If this constructor was not called with new we need to return the instance + // This will not harm when the constructor has been called with new as the returned value is ignored + return instance; + }; + + constr.prototype = proto; + constr.super = superProto; + constr.extend = this.extend; + + return constr; + } + + /** + * Creates a mixin from multiple super prototypes. + * + * @memberof Chartist.Class + * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. + * @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. + * @returns {Function} Constructor function of the newly created mixin class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * + * var KCal = Class.extend({ + * sugar: 0, + * + * constructor: function(sugar) { + * this.sugar = sugar; + * }, + * + * get kcal() { + * return [this.sugar * 4, 'kcal'].join(''); + * } + * }); + * + * var Nameable = Class.extend({ + * name: undefined, + * + * constructor: function(name) { + * this.name = name; + * } + * }); + * + * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { + * constructor: function(name, length, sugar) { + * Nameable.prototype.constructor.call(this, name); + * Banana.prototype.constructor.call(this, length, sugar); + * }, + * + * toString: function() { + * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); + * } + * }); + * + * + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); + * console.log(superBanana.toString()); + * + */ + function mix(mixProtoArr, properties) { + if(this !== Chartist.Class) { + throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); + } + + // Make sure our mixin prototypes are the class objects and not the constructors + var superPrototypes = [{}] + .concat(mixProtoArr) + .map(function (prototype) { + return prototype instanceof Function ? prototype.prototype : prototype; + }); + + var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); + // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype + delete mixedSuperProto.constructor; + return this.extend(properties, mixedSuperProto); + } + + // Variable argument list clones args > 0 into args[0] and retruns modified args[0] + function cloneDefinitions() { + var args = listToArray(arguments); + var target = args[0]; + + args.splice(1, args.length - 1).forEach(function (source) { + Object.getOwnPropertyNames(source).forEach(function (propName) { + // If this property already exist in target we delete it first + delete target[propName]; + // Define the property with the descriptor from source + Object.defineProperty(target, propName, + Object.getOwnPropertyDescriptor(source, propName)); + }); + }); + + return target; + } + + Chartist.Class = { + extend: extend, + mix: mix, + cloneDefinitions: cloneDefinitions + }; + + }(window, document, Chartist));;/** + * Base for all chart classes. + * + * @module Chartist.Base + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container + /** + * Updates the chart which currently does a full reconstruction of the SVG DOM + * + * @memberof Chartist.Line + */ + function update() { + this.createChart(this.optionsProvider.currentOptions); + } + + /** + * 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. + * + * @memberof Chartist.Line + */ + function detach() { + window.removeEventListener('resize', this.update); + this.optionsProvider.removeMediaQueryListeners(); + } + + /** + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. + * + * @memberof Chartist.Line + * @param {String} event Name of the event. Check the examples for supported events. + * @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. + */ + function on(event, handler) { + this.eventEmitter.addEventHandler(event, handler); + } + + /** + * 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. + * + * @memberof Chartist.Line + * @param {String} event Name of the event for which a handler should be removed + * @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. + */ + function off(event, handler) { + this.eventEmitter.removeEventHandler(event, handler); + } + + /** + * Constructor of chart base class. + * + * @param query + * @param data + * @param options + * @param responsiveOptions + * @constructor + */ + function Base(query, data, options, responsiveOptions) { + this.container = Chartist.querySelector(query); + this.data = data; + this.options = options; + this.responsiveOptions = responsiveOptions; + this.eventEmitter = Chartist.EventEmitter(); + + window.addEventListener('resize', this.update.bind(this)); + + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + // TODO: Remove default options parameter from optionsProvider + this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter); + this.createChart(this.optionsProvider.currentOptions); + }.bind(this), 0); + } + + // Creating the chart base class + Chartist.Base = Chartist.Class.extend({ + constructor: Base, + optionsProvider: undefined, + container: undefined, + svg: undefined, + eventEmitter: undefined, + createChart: function() { + throw new Error('Base chart type can\'t be instantiated!'); + }, + update: update, + detach: detach, + on: on, + off: off, + version: Chartist.version + }); + }(window, document, Chartist));;/** * Chartist SVG module for simple SVG DOM abstraction * @@ -1096,8 +1415,191 @@ (function(window, document, Chartist){ 'use strict'; + var defaultOptions = { + axisX: { + offset: 10, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 15, + showLabel: true, + showGrid: true, + labelAlign: 'right', + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 30 + }, + width: undefined, + height: undefined, + showLine: true, + showPoint: true, + showArea: false, + areaBase: 0, + lineSmooth: true, + low: undefined, + high: undefined, + chartPadding: 5, + classNames: { + chart: 'ct-chart-line', + label: 'ct-label', + series: 'ct-series', + line: 'ct-line', + point: 'ct-point', + area: 'ct-area', + grid: 'ct-grid', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var xAxisOffset, + yAxisOffset, + seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg object + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options); + + xAxisOffset = options.axisX.offset; + if (options.axisX.showLabel) { + xAxisOffset += Chartist.calculateLabelOffset( + this.svg, + this.data.labels, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisX.labelInterpolationFnc, + 'height' + ); + } + + yAxisOffset = options.axisY.offset; + if (options.axisY.showLabel) { + yAxisOffset += Chartist.calculateLabelOffset( + this.svg, + bounds.values, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisY.labelInterpolationFnc, + 'width' + ); + } + + var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + // Start drawing + var labels = this.svg.elem('g'), + grid = this.svg.elem('g'); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var p, + pathCoordinates = [], + point; + + for (var j = 0; j < normalizedData[i].length; j++) { + p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); + pathCoordinates.push(p.x, p.y); + + //If we should show points we need to create them now to avoid secondary loop + // Small offset for Firefox to render squares correctly + if (options.showPoint) { + point = seriesGroups[i].elem('line', { + x1: p.x, + y1: p.y, + x2: p.x + 0.01, + y2: p.y + }, options.classNames.point).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'point', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: point, + x: p.x, + y: p.y + }); + } + } + + // TODO: Nicer handling of conditions, maybe composition? + if (options.showLine || options.showArea) { + // TODO: We should add a path API in the SVG library for easier path creation + var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; + + // If smoothed path and path has more than two points then use catmull rom to bezier algorithm + if (options.lineSmooth && pathCoordinates.length > 4) { + + var cr = Chartist.catmullRom2bezier(pathCoordinates); + for(var k = 0; k < cr.length; k++) { + pathElements.push('C' + cr[k].join()); + } + } else { + for(var l = 3; l < pathCoordinates.length; l += 2) { + pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); + } + } + + if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); + + // If we need to draw area shapes we just make a copy of our pathElements SVG path array + var areaPathElements = pathElements.slice(); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); + // And splice our new area path array to add the missing path elements to close the area shape + areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); + areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; + areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + + // Create the new path for the area shape with the area class from the options + seriesGroups[i].elem('path', { + d: areaPathElements.join('') + }, options.classNames.area, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } + + if(options.showLine) { + seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + } + } + } + } + /** - * This method creates a new line chart and returns API object that you can use for later changes. + * This method creates a new line chart. * * @memberof Chartist.Line * @param {String|Node} query A selector query string or directly a DOM element @@ -1187,7 +1689,7 @@ * }; * * // 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 - * Chartist.Line('.ct-chart', data, options); + * new Chartist.Line('.ct-chart', data, options); * * @example * // Create a line chart with responsive options @@ -1223,270 +1725,22 @@ * }] * ]; * - * Chartist.Line('.ct-chart', data, null, responsiveOptions); + * new Chartist.Line('.ct-chart', data, null, responsiveOptions); * */ - Chartist.Line = function (query, data, options, responsiveOptions) { - - var defaultOptions = { - axisX: { - offset: 10, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 15, - showLabel: true, - showGrid: true, - labelAlign: 'right', - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 30 - }, - width: undefined, - height: undefined, - showLine: true, - showPoint: true, - showArea: false, - areaBase: 0, - lineSmooth: true, - low: undefined, - high: undefined, - chartPadding: 5, - classNames: { - chart: 'ct-chart-line', - label: 'ct-label', - series: 'ct-series', - line: 'ct-line', - point: 'ct-point', - area: 'ct-area', - grid: 'ct-grid', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }, - optionsProvider, - container = Chartist.querySelector(query), - svg, - eventEmitter = Chartist.EventEmitter(); - - function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length); - - // Create new svg object - svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart); - - // initialize bounds - bounds = Chartist.getBounds(svg, normalizedData, options); - - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - svg, - data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } - - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } - - var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset); - // Start drawing - var labels = svg.elem('g'), - grid = svg.elem('g'); - - Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); - - // Draw the series - // initialize series groups - for (var i = 0; i < data.series.length; i++) { - seriesGroups[i] = svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var p, - pathCoordinates = [], - point; - - for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); - pathCoordinates.push(p.x, p.y); - - //If we should show points we need to create them now to avoid secondary loop - // Small offset for Firefox to render squares correctly - if (options.showPoint) { - point = seriesGroups[i].elem('line', { - x1: p.x, - y1: p.y, - x2: p.x + 0.01, - y2: p.y - }, options.classNames.point).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); - - eventEmitter.emit('draw', { - type: 'point', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: point, - x: p.x, - y: p.y - }); - } - } - - // TODO: Nicer handling of conditions, maybe composition? - if (options.showLine || options.showArea) { - // TODO: We should add a path API in the SVG library for easier path creation - var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; - - // If smoothed path and path has more than two points then use catmull rom to bezier algorithm - if (options.lineSmooth && pathCoordinates.length > 4) { - - var cr = Chartist.catmullRom2bezier(pathCoordinates); - for(var k = 0; k < cr.length; k++) { - pathElements.push('C' + cr[k].join()); - } - } else { - for(var l = 3; l < pathCoordinates.length; l += 2) { - pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); - } - } - - if(options.showArea) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); - - // If we need to draw area shapes we just make a copy of our pathElements SVG path array - var areaPathElements = pathElements.slice(); - - // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); - // And splice our new area path array to add the missing path elements to close the area shape - areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); - areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; - areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); - - // Create the new path for the area shape with the area class from the options - seriesGroups[i].elem('path', { - d: areaPathElements.join('') - }, options.classNames.area, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - } - - if(options.showLine) { - seriesGroups[i].elem('path', { - d: pathElements.join('') - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - } - } - } - } - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Line - */ - function update() { - createChart(optionsProvider.currentOptions); - } - - /** - * 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. - * - * @memberof Chartist.Line - */ - function detach() { - window.removeEventListener('resize', update); - optionsProvider.removeMediaQueryListeners(); - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Line - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - eventEmitter.addEventHandler(event, handler); - } - - /** - * 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. - * - * @memberof Chartist.Line - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - eventEmitter.removeEventHandler(event, handler); - } - - // Initialization of the chart - - window.addEventListener('resize', update); - - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - createChart(optionsProvider.currentOptions); - }, 0); - - // Public members of the module (revealing module pattern style) - var api = { - version: Chartist.version, - update: update, - on: on, - off: off, - detach: detach - }; + function Line(query, data, options, responsiveOptions) { + Chartist.Line.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } - container.chartist = api; - return api; - }; + // Creating line chart type in Chartist namespace + Chartist.Line = Chartist.Base.extend({ + constructor: Line, + createChart: createChart + }); }(window, document, Chartist)); ;/** @@ -1498,6 +1752,140 @@ (function(window, document, Chartist){ 'use strict'; + var defaultOptions = { + axisX: { + offset: 10, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 15, + showLabel: true, + showGrid: true, + labelAlign: 'right', + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 40 + }, + width: undefined, + height: undefined, + high: undefined, + low: undefined, + chartPadding: 5, + seriesBarDistance: 15, + classNames: { + chart: 'ct-chart-bar', + label: 'ct-label', + series: 'ct-series', + bar: 'ct-bar', + thin: 'ct-thin', + thick: 'ct-thick', + grid: 'ct-grid', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var xAxisOffset, + yAxisOffset, + seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg element + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); + + xAxisOffset = options.axisX.offset; + if (options.axisX.showLabel) { + xAxisOffset += Chartist.calculateLabelOffset( + this.svg, + this.data.labels, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisX.labelInterpolationFnc, + 'height' + ); + } + + yAxisOffset = options.axisY.offset; + if (options.axisY.showLabel) { + yAxisOffset += Chartist.calculateLabelOffset( + this.svg, + bounds.values, + [options.classNames.label, options.classNames.horizontal].join(' '), + options.axisY.labelInterpolationFnc, + 'width' + ); + } + + var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + // Start drawing + var labels = this.svg.elem('g'), + grid = this.svg.elem('g'), + // Projected 0 point + zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. + var biPol = i - (this.data.series.length - 1) / 2, + // Half of the period with between vertical grid lines used to position bars + periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; + + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + for(var j = 0; j < normalizedData[i].length; j++) { + var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), + bar; + + // Offset to center bar between grid lines and using bi-polar offset for multiple series + // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors + p.x += periodHalfWidth + (biPol * options.seriesBarDistance); + + bar = seriesGroups[i].elem('line', { + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }, options.classNames.bar).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'bar', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: bar, + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }); + } + } + } + /** * This method creates a new bar chart and returns API object that you can use for later changes. * @@ -1578,11 +1966,11 @@ * }; * * // 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. - * Chartist.Bar('.ct-chart', data); + * new Chartist.Bar('.ct-chart', data); * * @example * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 - * Chartist.Bar('.ct-chart', { + * new Chartist.Bar('.ct-chart', { * labels: [1, 2, 3, 4, 5, 6, 7], * series: [ * [1, 3, 2, -5, -3, 1, -6], @@ -1595,228 +1983,209 @@ * }); * */ - Chartist.Bar = function (query, data, options, responsiveOptions) { - - var defaultOptions = { - axisX: { - offset: 10, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 15, - showLabel: true, - showGrid: true, - labelAlign: 'right', - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 40 - }, - width: undefined, - height: undefined, - high: undefined, - low: undefined, - chartPadding: 5, - seriesBarDistance: 15, - classNames: { - chart: 'ct-chart-bar', - label: 'ct-label', - series: 'ct-series', - bar: 'ct-bar', - thin: 'ct-thin', - thick: 'ct-thick', - grid: 'ct-grid', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }, - optionsProvider, - container = Chartist.querySelector(query), - svg, - eventEmitter = Chartist.EventEmitter(); - - function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length); + function Bar(query, data, options, responsiveOptions) { + Chartist.Bar.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } - // Create new svg element - svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart); + // Creating bar chart type in Chartist namespace + Chartist.Bar = Chartist.Base.extend({ + constructor: Bar, + createChart: createChart + }); - // initialize bounds - bounds = Chartist.getBounds(svg, normalizedData, options, 0); + }(window, document, Chartist)); + ;/** + * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts + * + * @module Chartist.Pie + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - svg, - data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } + var defaultOptions = { + width: undefined, + height: undefined, + chartPadding: 5, + classNames: { + chart: 'ct-chart-pie', + series: 'ct-series', + slice: 'ct-slice', + donut: 'ct-donut', + label: 'ct-label' + }, + startAngle: 0, + total: undefined, + donut: false, + donutWidth: 60, + showLabel: true, + labelOffset: 0, + labelInterpolationFnc: Chartist.noop, + labelOverflow: false, + labelDirection: 'neutral' + }; - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } + function determineAnchorPosition(center, label, direction) { + var toTheRight = label.x > center.x; - var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset); - // Start drawing - var labels = svg.elem('g'), - grid = svg.elem('g'), - // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - - Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter); - - // Draw the series - // initialize series groups - for (var i = 0; i < data.series.length; i++) { - // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = i - (data.series.length - 1) / 2, - // Half of the period with between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; - - seriesGroups[i] = svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': data.series[i].name - }, Chartist.xmlNs.uri); - } + if(toTheRight && direction === 'explode' || + !toTheRight && direction === 'implode') { + return 'start'; + } else if(toTheRight && direction === 'implode' || + !toTheRight && direction === 'explode') { + return 'end'; + } else { + return 'middle'; + } + } - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); + function createChart(options) { + var seriesGroups = [], + chartRect, + radius, + labelRadius, + totalDataSum, + startAngle = options.startAngle, + dataArray = Chartist.getDataArray(this.data); + + // Create SVG.js draw + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + // Calculate charting rect + chartRect = Chartist.createChartRect(this.svg, options, 0, 0); + // Get biggest circle radius possible within chartRect + radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + // Calculate total of all series to get reference value or use total reference from optional options + totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { + return previousValue + currentValue; + }, 0); - for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), - bar; + // 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 ? options.donutWidth / 2 : 0; + + // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius + // see https://github.com/gionkunz/chartist-js/issues/21 + labelRadius = options.donut ? radius : radius / 2; + // Add the offset to the labelRadius where a negative offset means closed to the center of the chart + labelRadius += options.labelOffset; + + // Calculate end angle based on total sum and current data value and offset with padding + var center = { + x: chartRect.x1 + chartRect.width() / 2, + y: chartRect.y2 + chartRect.height() / 2 + }; - // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors - p.x += periodHalfWidth + (biPol * options.seriesBarDistance); + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = this.data.series.filter(function(val) { + return val !== 0; + }).length === 1; - bar = seriesGroups[i].elem('line', { - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }, options.classNames.bar).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g', null, null, true); - eventEmitter.emit('draw', { - type: 'bar', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: bar, - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }); - } + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); } - } - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Bar - */ - function update() { - createChart(optionsProvider.currentOptions); - } + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle + // with Z and use 359.99 degrees + if(endAngle - startAngle === 360) { + endAngle -= 0.01; + } - /** - * 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. - * - * @memberof Chartist.Bar - */ - function detach() { - window.removeEventListener('resize', update); - optionsProvider.removeMediaQueryListeners(); - } + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), + arcSweep = endAngle - startAngle <= 180 ? '0' : '1', + d = [ + // Start at the end point from the cartesian coordinates + 'M', end.x, end.y, + // Draw arc + 'A', radius, radius, 0, arcSweep, 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 === false) { + d.push('L', center.x, center.y); + } - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Bar - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - eventEmitter.addEventHandler(event, handler); - } + // Create the SVG path + // If this is a donut chart we add the donut class, otherwise just a regular slice + var path = seriesGroups[i].elem('path', { + d: d.join(' ') + }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); - /** - * 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. - * - * @memberof Chartist.Bar - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - eventEmitter.removeEventHandler(event, handler); - } + // Adding the pie series value to the path + path.attr({ + 'value': dataArray[i] + }, Chartist.xmlNs.uri); - // Initialization of the chart + // If this is a donut, we add the stroke-width as style attribute + if(options.donut === true) { + path.attr({ + 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' + }); + } - window.addEventListener('resize', update); + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'slice', + value: dataArray[i], + totalDataSum: totalDataSum, + index: i, + group: seriesGroups[i], + element: path, + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - createChart(optionsProvider.currentOptions); - }, 0); + // If we need to show labels we need to add the label for this slice now + if(options.showLabel) { + // Position at the labelRadius distance from center and between start and end angle + var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), + interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); - // Public members of the module (revealing module pattern style) - var api = { - version: Chartist.version, - update: update, - on: on, - off: off, - detach: detach - }; + var labelElement = seriesGroups[i].elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); - container.chartist = api; - return api; - }; + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } - }(window, document, Chartist)); - ;/** - * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts - * - * @module Chartist.Pie - */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; + // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // (except for last slice) + startAngle = endAngle; + } + } /** * This method creates a new pie chart and returns an object that can be used to redraw the chart. @@ -1865,13 +2234,13 @@ * * @example * // Simple pie chart example with four series - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] * }); * * @example * // Drawing a donut chart - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] * }, { * donut: true @@ -1879,7 +2248,7 @@ * * @example * // Using donut, startAngle and total to draw a gauge chart - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [20, 10, 30, 40] * }, { * donut: true, @@ -1890,7 +2259,7 @@ * * @example * // Drawing a pie chart with padding and labels that are outside the pie - * Chartist.Pie('.ct-chart', { + * new Chartist.Pie('.ct-chart', { * series: [20, 10, 30, 40] * }, { * chartPadding: 30, @@ -1898,268 +2267,24 @@ * labelDirection: 'explode' * }); */ - Chartist.Pie = function (query, data, options, responsiveOptions) { - - var defaultOptions = { - width: undefined, - height: undefined, - chartPadding: 5, - classNames: { - chart: 'ct-chart-pie', - series: 'ct-series', - slice: 'ct-slice', - donut: 'ct-donut', - label: 'ct-label' - }, - startAngle: 0, - total: undefined, - donut: false, - donutWidth: 60, - showLabel: true, - labelOffset: 0, - labelInterpolationFnc: Chartist.noop, - labelOverflow: false, - labelDirection: 'neutral' - }, - optionsProvider, - container = Chartist.querySelector(query), - svg, - eventEmitter = Chartist.EventEmitter(); - - function determineAnchorPosition(center, label, direction) { - var toTheRight = label.x > center.x; - - if(toTheRight && direction === 'explode' || - !toTheRight && direction === 'implode') { - return 'start'; - } else if(toTheRight && direction === 'implode' || - !toTheRight && direction === 'explode') { - return 'end'; - } else { - return 'middle'; - } - } - - function createChart(options) { - var seriesGroups = [], - chartRect, - radius, - labelRadius, - totalDataSum, - startAngle = options.startAngle, - dataArray = Chartist.getDataArray(data); - - // Create SVG.js draw - svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart); - // Calculate charting rect - chartRect = Chartist.createChartRect(svg, options, 0, 0); - // Get biggest circle radius possible within chartRect - radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); - // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { - return previousValue + currentValue; - }, 0); - - // 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 ? options.donutWidth / 2 : 0; - - // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius - // see https://github.com/gionkunz/chartist-js/issues/21 - labelRadius = options.donut ? radius : radius / 2; - // Add the offset to the labelRadius where a negative offset means closed to the center of the chart - labelRadius += options.labelOffset; - - // Calculate end angle based on total sum and current data value and offset with padding - var center = { - x: chartRect.x1 + chartRect.width() / 2, - y: chartRect.y2 + chartRect.height() / 2 - }; - - // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = data.series.filter(function(val) { - return val !== 0; - }).length === 1; - - // Draw the series - // initialize series groups - for (var i = 0; i < data.series.length; i++) { - seriesGroups[i] = svg.elem('g', null, null, true); - - // If the series is an object and contains a name we add a custom attribute - if(data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var endAngle = startAngle + dataArray[i] / totalDataSum * 360; - // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle - // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; - } - - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), - end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), - arcSweep = endAngle - startAngle <= 180 ? '0' : '1', - d = [ - // Start at the end point from the cartesian coordinates - 'M', end.x, end.y, - // Draw arc - 'A', radius, radius, 0, arcSweep, 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 === false) { - d.push('L', center.x, center.y); - } - - // Create the SVG path - // If this is a donut chart we add the donut class, otherwise just a regular slice - var path = seriesGroups[i].elem('path', { - d: d.join(' ') - }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); - - // Adding the pie series value to the path - path.attr({ - 'value': dataArray[i] - }, Chartist.xmlNs.uri); - - // If this is a donut, we add the stroke-width as style attribute - if(options.donut === true) { - path.attr({ - 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' - }); - } - - // Fire off draw event - eventEmitter.emit('draw', { - type: 'slice', - value: dataArray[i], - totalDataSum: totalDataSum, - index: i, - group: seriesGroups[i], - element: path, - center: center, - radius: radius, - startAngle: startAngle, - endAngle: endAngle - }); - - // If we need to show labels we need to add the label for this slice now - if(options.showLabel) { - // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i); - - var labelElement = seriesGroups[i].elem('text', { - dx: labelPosition.x, - dy: labelPosition.y, - 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) - }, options.classNames.label).text('' + interpolatedValue); - - // Fire off draw event - eventEmitter.emit('draw', { - type: 'label', - index: i, - group: seriesGroups[i], - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y - }); - } - - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues - // (except for last slice) - startAngle = endAngle; - } - } - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Pie - * - */ - function update() { - createChart(optionsProvider.currentOptions); - } - - /** - * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts. - * - * @memberof Chartist.Pie - */ - function detach() { - window.removeEventListener('resize', update); - optionsProvider.removeMediaQueryListeners(); - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Pie - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - eventEmitter.addEventHandler(event, handler); - } - - /** - * 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. - * - * @memberof Chartist.Pie - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - eventEmitter.removeEventHandler(event, handler); - } - - // Initialization of the chart - - window.addEventListener('resize', update); - - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter); - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - createChart(optionsProvider.currentOptions); - }, 0); - - // Public members of the module (revealing module pattern style) - var api = { - version: Chartist.version, - update: update, - on: on, - off: off, - detach: detach - }; + function Pie(query, data, options, responsiveOptions) { + Chartist.Pie.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } - container.chartist = api; - return api; - }; + // Creating pie chart type in Chartist namespace + Chartist.Pie = Chartist.Base.extend({ + constructor: Pie, + createChart: createChart, + determineAnchorPosition: determineAnchorPosition + }); }(window, document, Chartist)); + return Chartist; })); diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index be412b9a..1939712b 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.2.3 +/* Chartist.js 0.2.4 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 4fe9bcbf..57ff58b7 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.2.3 +/* Chartist.js 0.2.4 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.2.3",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return a.height()-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";c.xmlNs={qualifiedName:"xmlns:ct",prefix:"ct",uri:"http://gionkunz.github.com/chartist-js/ct"},c.Svg=function(a,d,e,f,g){function h(a,b,d){return Object.keys(b).forEach(function(e){void 0!==b[e]&&(d?a.setAttributeNS(d,[c.xmlNs.prefix,":",e].join(""),b[e]):a.setAttribute(e,b[e]))}),a}function i(a,d,e,f,g){var i=b.createElementNS(v,a);return"svg"===a&&i.setAttributeNS(w,c.xmlNs.qualifiedName,c.xmlNs.uri),f&&(g&&f.firstChild?f.insertBefore(i,f.firstChild):f.appendChild(i)),d&&h(i,d),e&&q(i,e),i}function j(a,d,e,f,g,h,i,j){if("string"==typeof a){var k=b.createElement("div");k.innerHTML=a,a=k.firstChild}a.setAttribute("xmlns",x);var l=c.Svg("foreignObject",{x:d,y:e,width:f,height:g},h,i,j);return l._node.appendChild(a),l}function k(a,c){a.appendChild(b.createTextNode(c))}function l(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function m(a){a.parentNode.removeChild(a)}function n(a,b){a.parentNode.replaceChild(b,a)}function o(a,b,c){c&&a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)}function p(a){return a.getAttribute("class")?a.getAttribute("class").trim().split(/\s+/):[]}function q(a,b){a.setAttribute("class",p(a).concat(b.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" "))}function r(a,b){var c=b.trim().split(/\s+/);a.setAttribute("class",p(a).filter(function(a){return-1===c.indexOf(a)}).join(" "))}function s(a){a.setAttribute("class","")}function t(a){return a.clientHeight||Math.round(a.getBBox().height)||a.parentNode.clientHeight}function u(a){return a.clientWidth||Math.round(a.getBBox().width)||a.parentNode.clientWidth}var v="http://www.w3.org/2000/svg",w="http://www.w3.org/2000/xmlns/",x="http://www.w3.org/1999/xhtml";return{_node:i(a,d,e,f?f._node:void 0,g),_parent:f,parent:function(){return this._parent},attr:function(a,b){return h(this._node,a,b),this},empty:function(){return l(this._node),this},remove:function(){return m(this._node),this.parent()},replace:function(a){return a._parent=this._parent,n(this._node,a._node),a},append:function(a,b){return a._parent=this,o(this._node,a._node,b),a},elem:function(a,b,d,e){return c.Svg(a,b,d,this,e)},foreignObject:function(a,b,c,d,e,f,g){return j(a,b,c,d,e,f,this,g)},text:function(a){return k(this._node,a),this},addClass:function(a){return q(this._node,a),this},removeClass:function(a){return r(this._node,a),this},removeAllClasses:function(){return s(this._node),this},classes:function(){return p(this._node)},height:function(){return t(this._node)},width:function(){return u(this._node)}}}}(window,document,a),function(a,b,c){"use strict";c.Line=function(b,d,e,f){function g(a){var b,e,f,g=[],h=c.normalizeDataArray(c.getDataArray(d),d.labels.length);m=c.createSvg(o,a.width,a.height,a.classNames.chart),f=c.getBounds(m,h,a),b=a.axisX.offset,a.axisX.showLabel&&(b+=c.calculateLabelOffset(m,d.labels,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisX.labelInterpolationFnc,"height")),e=a.axisY.offset,a.axisY.showLabel&&(e+=c.calculateLabelOffset(m,f.values,[a.classNames.label,a.classNames.horizontal].join(" "),a.axisY.labelInterpolationFnc,"width"));var i=c.createChartRect(m,a,b,e),j=m.elem("g"),k=m.elem("g");c.createXAxis(i,d,k,j,a,p),c.createYAxis(i,f,k,j,e,a,p);for(var l=0;l4)for(var u=c.catmullRom2bezier(r),v=0;va.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function h(a){var b,e,f,h,i=[],j=a.startAngle,k=c.getDataArray(d);n=c.createSvg(p,a.width,a.height,a.classNames.chart),b=c.createChartRect(n,a,0,0),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===d.series.filter(function(a){return 0!==a}).length,o=0;o=r-j?"0":"1",v=["M",t.x,t.y,"A",e,e,0,u,0,s.x,s.y];a.donut===!1&&v.push("L",l.x,l.y);var w=i[o].elem("path",{d:v.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(w.attr({value:k[o]},c.xmlNs.uri),a.donut===!0&&w.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),q.emit("draw",{type:"slice",value:k[o],totalDataSum:h,index:o,group:i[o],element:w,center:l,radius:e,startAngle:j,endAngle:r}),a.showLabel){var x=c.polarToCartesian(l.x,l.y,f,j+(r-j)/2),y=a.labelInterpolationFnc(d.labels?d.labels[o]:k[o],o),z=i[o].elem("text",{dx:x.x,dy:x.y,"text-anchor":g(l,x,a.labelDirection)},a.classNames.label).text(""+y);q.emit("draw",{type:"label",index:o,group:i[o],element:z,text:""+y,x:x.x,y:x.y})}j=r}}function i(){h(m.currentOptions)}function j(){a.removeEventListener("resize",i),m.removeMediaQueryListeners()}function k(a,b){q.addEventHandler(a,b)}function l(a,b){q.removeEventHandler(a,b)}var m,n,o={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"},p=c.querySelector(b),q=c.EventEmitter();a.addEventListener("resize",i),m=c.optionsProvider(o,e,f,q),setTimeout(function(){h(m.currentOptions)},0);var r={version:c.version,update:i,on:k,off:l,detach:j};return p.chartist=r,r}}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.2.4",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return a.height()-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var q=c.catmullRom2bezier(n),r=0;ra.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index da920476..0f33e73d 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24405,"pos":24391,"col":12,"line":640,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","Object","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","concat","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","Line","createChart","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","slice","areaBaseProjected","area","line","update","detach","removeEventListener","on","off","addEventListener","setTimeout","api","chartist","Bar","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","thin","thick","Pie","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","labelPosition","labelDirection","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.3\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.2.3';\n\n (function (window, document, Chartist) {\n 'use strict';\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 svg.height() - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, label[offsetFnc]());\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 * This method creates a new line chart and returns API object that you can use for later changes.\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * Chartist.Line('.ct-chart', data, options);\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 adition 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 * Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n Chartist.Line = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg object\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g');\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\n }\n }\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 * @memberof Chartist.Line\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Line\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 eventEmitter.addEventHandler(event, handler);\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.Line\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * 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 * 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 * heigh: 10\n * });\n *\n */\n Chartist.Bar = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length);\n\n // Create new svg element\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n svg,\n data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = svg.elem('g'),\n grid = svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, data, grid, labels, options, eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\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 = i - (data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n }\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 * @memberof Chartist.Bar\n */\n function update() {\n createChart(optionsProvider.currentOptions);\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.Bar\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Bar\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 eventEmitter.addEventHandler(event, handler);\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.Bar\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\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 * 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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\n *\n * @example\n * // Simple pie chart example with four series\n * Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * 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 * 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 * Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n */\n Chartist.Pie = function (query, data, options, responsiveOptions) {\n\n var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n },\n optionsProvider,\n container = Chartist.querySelector(query),\n svg,\n eventEmitter = Chartist.EventEmitter();\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(data);\n\n // Create SVG.js draw\n svg = Chartist.createSvg(container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < data.series.length; i++) {\n seriesGroups[i] = svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(data.labels ? data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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 eventEmitter.emit('draw', {\n type: 'label',\n index: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\n }\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 * @memberof Chartist.Pie\n *\n */\n function update() {\n createChart(optionsProvider.currentOptions);\n }\n\n /**\n * This method will detach the chart from any event listeners that have been added. This includes window.resize and media query listeners for the responsive options. Call this method in order to de-initialize dynamically created / removed charts.\n *\n * @memberof Chartist.Pie\n */\n function detach() {\n window.removeEventListener('resize', update);\n optionsProvider.removeMediaQueryListeners();\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.Pie\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 eventEmitter.addEventHandler(event, handler);\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.Pie\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 eventEmitter.removeEventHandler(event, handler);\n }\n\n // Initialization of the chart\n\n window.addEventListener('resize', update);\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 optionsProvider = Chartist.optionsProvider(defaultOptions, options, responsiveOptions, eventEmitter);\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 setTimeout(function() {\n createChart(optionsProvider.currentOptions);\n }, 0);\n\n // Public members of the module (revealing module pattern style)\n var api = {\n version: Chartist.version,\n update: update,\n on: on,\n off: off,\n detach: detach\n };\n\n container.chartist = api;\n return api;\n };\n\n }(window, document, Chartist));\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24464,"pos":24450,"col":12,"line":641,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24464,"pos":24450,"col":12,"line":641,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","on","off","Base","addEventListener","bind","setTimeout","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","thin","thick","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","labelPosition","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.4\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.2.4';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 svg.height() - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, label[offsetFnc]());\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 * @returns {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\\'s 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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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\\'s 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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\\'s 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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\n cloneDefinitions: cloneDefinitions\n };\n\n }(window, document, Chartist));;/**\n * Base for all chart classes.\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 * @memberof Chartist.Line\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', this.update);\n this.optionsProvider.removeMediaQueryListeners();\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.Line\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 }\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.Line\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 }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\n this.options = options;\n this.responsiveOptions = responsiveOptions;\n this.eventEmitter = Chartist.EventEmitter();\n\n window.addEventListener('resize', this.update.bind(this));\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 });\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n this.data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g');\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n this.data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * heigh: 10\n * });\n *\n */\n function Bar(query, data, options, responsiveOptions) {\n Chartist.Bar.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file From e9cf042c0ba7fb656e42ed0e36fca9be9605965a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Oct 2014 16:14:24 +0200 Subject: [PATCH 045/593] Refactored core and line and bar charts to include foreignObject labels with fixed offset --- source/scripts/chartist.bar.js | 45 +++---- source/scripts/chartist.core.js | 127 ++++++++------------ source/scripts/chartist.line.js | 43 ++----- source/scripts/site/chartist-guy.js | 5 +- source/site/examples/example-gallery-one.js | 11 +- source/site/examples/example-gallery-two.js | 8 +- 6 files changed, 85 insertions(+), 154 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 71e53086..9fec38d2 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -9,18 +9,25 @@ var defaultOptions = { axisX: { - offset: 10, + offset: 30, + labelOffset: { + x: 0, + y: 5 + }, showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop }, axisY: { - offset: 15, + offset: 40, + labelOffset: { + x: -10, + y: -15 + }, showLabel: true, showGrid: true, - labelAlign: 'right', labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 40 + scaleMinSpace: 30 }, width: undefined, height: undefined, @@ -42,9 +49,7 @@ }; function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], + var seriesGroups = [], bounds, normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); @@ -54,29 +59,7 @@ // initialize bounds bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - this.svg, - this.data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } - - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - this.svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } - - var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing var labels = this.svg.elem('g'), grid = this.svg.elem('g'), @@ -84,7 +67,7 @@ zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter); // Draw the series // initialize series groups diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 1410f268..a7d7c136 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -318,40 +318,6 @@ Chartist.version = '0.2.4'; return bounds; }; - /** - * Calculate the needed offset to fit in the labels - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Object} labelClass All css classes of the label - * @param {Function} labelInterpolationFnc The function that interpolates the label value - * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length - * @return {Number} The number that represents the label offset in pixels - */ - Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) { - var offset = 0; - for (var i = 0; i < data.length; i++) { - // If interpolation function returns falsy value we skipp this label - var interpolated = labelInterpolationFnc(data[i], i); - if (!interpolated && interpolated !== 0) { - continue; - } - - var label = svg.elem('text', { - dx: 0, - dy: 0 - }, labelClass).text('' + interpolated); - - // Check if this is the largest label and update offset - offset = Math.max(offset, label[offsetFnc]()); - // Remove label after offset Calculation - label.remove(); - } - - return offset; - }; - /** * Calculate cartesian coordinates of polar coordinates * @@ -377,14 +343,12 @@ Chartist.version = '0.2.4'; * @memberof Chartist.Core * @param {Object} svg The svg element for the chart * @param {Object} options The Object that contains all the optional values for the chart - * @param {Number} xAxisOffset The offset of the x-axis to the border of the svg element - * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ - Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) { + Chartist.createChartRect = function (svg, options) { return { - x1: options.chartPadding + yAxisOffset, - y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset, + x1: options.chartPadding + (options.axisY ? options.axisY.offset : 0), + y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - (options.axisX ? options.axisX.offset : 0), x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, y2: options.chartPadding, width: function () { @@ -396,6 +360,11 @@ Chartist.version = '0.2.4'; }; }; + Chartist.createLabel = function(parent, text, attributes, className) { + var content = '' + text + ''; + return parent.foreignObject(content, attributes); + }; + /** * Generate grid lines and labels for the x-axis into grid and labels group SVG elements * @@ -410,8 +379,9 @@ Chartist.version = '0.2.4'; // Create X-Axis data.labels.forEach(function (value, index) { var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - space = chartRect.width() / data.labels.length, - pos = chartRect.x1 + space * index; + width = chartRect.width() / data.labels.length, + height = options.axisX.offset, + pos = chartRect.x1 + width * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -441,21 +411,18 @@ Chartist.version = '0.2.4'; } if (options.axisX.showLabel) { - // Use config offset for setting labels of - var labelPos = { - x: pos + 2, - y: 0 + var labelPosition = { + x: pos + options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y }; - var labelElement = labels.elem('text', { - dx: labelPos.x - }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue); - - // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos - labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset; - labelElement.attr({ - dy: labelPos.y - }); + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.horizontal].join(' ')); eventEmitter.emit('draw', { type: 'label', @@ -464,9 +431,15 @@ Chartist.version = '0.2.4'; group: labels, element: labelElement, text: '' + interpolatedValue, - x: labelPos.x, - y: labelPos.y, - space: space + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.width; + } }); } }); @@ -480,15 +453,15 @@ Chartist.version = '0.2.4'; * @param {Object} bounds All the values to set the bounds of the chart * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Number} offset Offset for the y-axis * @param {Object} options The Object that contains all the optional values for the chart */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) { + Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter) { // Create Y-Axis bounds.values.forEach(function (value, index) { var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - space = chartRect.height() / bounds.values.length, - pos = chartRect.y1 - space * index; + width = options.axisY.offset, + height = chartRect.height() / bounds.values.length, + pos = chartRect.y1 - height * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -518,18 +491,18 @@ Chartist.version = '0.2.4'; } if (options.axisY.showLabel) { - // Use calculated offset and include padding for label x position - // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier - var labelPos = { - x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, - y: pos - 2 + var labelPosition = { + x: options.chartPadding + options.axisY.labelOffset.x, + y: pos + options.axisY.labelOffset.y }; - var labelElement = labels.elem('text', { - dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, - dy: pos - 2, - 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start' - }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue); + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.vertical].join(' ')); eventEmitter.emit('draw', { type: 'label', @@ -538,9 +511,15 @@ Chartist.version = '0.2.4'; group: labels, element: labelElement, text: '' + interpolatedValue, - x: labelPos.x, - y: labelPos.y, - space: space + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.height; + } }); } }); diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 23dffc3c..9b8285a2 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -11,16 +11,23 @@ var defaultOptions = { axisX: { - offset: 10, + offset: 30, + labelOffset: { + x: 0, + y: 5 + }, showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop }, axisY: { - offset: 15, + offset: 40, + labelOffset: { + x: -10, + y: -15 + }, showLabel: true, showGrid: true, - labelAlign: 'right', labelInterpolationFnc: Chartist.noop, scaleMinSpace: 30 }, @@ -48,9 +55,7 @@ }; function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], + var seriesGroups = [], bounds, normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); @@ -60,35 +65,13 @@ // initialize bounds bounds = Chartist.getBounds(this.svg, normalizedData, options); - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - this.svg, - this.data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } - - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - this.svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } - - var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing var labels = this.svg.elem('g'), grid = this.svg.elem('g'); Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter); // Draw the series // initialize series groups diff --git a/source/scripts/site/chartist-guy.js b/source/scripts/site/chartist-guy.js index c3c87856..1fbf714f 100644 --- a/source/scripts/site/chartist-guy.js +++ b/source/scripts/site/chartist-guy.js @@ -7,7 +7,7 @@ height: 137, chartPadding: 10, axisX: { - offset: 0, + offset: 15, showLabel: true, showGrid: true, labelInterpolationFnc: function(n) { @@ -15,9 +15,10 @@ } }, axisY: { - offset: 5, + offset: 25, showLabel: true, showGrid: true, + scaleMinSpace: 15, labelInterpolationFnc: function(n) { return Math.round(n / 100000) / 10 + 'm.'; } diff --git a/source/site/examples/example-gallery-one.js b/source/site/examples/example-gallery-one.js index ce527d00..daeb09ea 100644 --- a/source/site/examples/example-gallery-one.js +++ b/source/site/examples/example-gallery-one.js @@ -8,13 +8,4 @@ var data = { ] }; -var options = { - axisX: { - offset: 15 - }, - axisY: { - offset: 15 - } -}; - -new Chartist.Line('.ct-chart', data, options); \ No newline at end of file +new Chartist.Line('.ct-chart', data); \ No newline at end of file diff --git a/source/site/examples/example-gallery-two.js b/source/site/examples/example-gallery-two.js index 1fe15ad7..e408db59 100644 --- a/source/site/examples/example-gallery-two.js +++ b/source/site/examples/example-gallery-two.js @@ -7,13 +7,7 @@ var data = { }; var options = { - seriesBarDistance: 5, - axisX: { - offset: 15 - }, - axisY: { - offset: 15 - } + seriesBarDistance: 5 }; new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file From 4f7f34e2eea291f3fef052cc3ac1e10f1be235c6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Oct 2014 16:15:24 +0200 Subject: [PATCH 046/593] Added shortcut to options.height if it's a pixel value --- source/scripts/chartist.core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index a7d7c136..96f9aa87 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -199,7 +199,7 @@ Chartist.version = '0.2.4'; * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return svg.height() - (options.chartPadding * 2) - options.axisX.offset; + return (Chartist.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset; }; /** From 73c2f5014c079a6df93fb54cbcafb9f43f8588c7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Oct 2014 16:25:43 +0200 Subject: [PATCH 047/593] Added number conversion of option.high and options.low and optimized scale loop, fixes parts of #72 --- source/scripts/chartist.core.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 96f9aa87..d508eaa2 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -250,8 +250,8 @@ Chartist.version = '0.2.4'; bounds = Chartist.getHighLow(normalizedData); // Overrides of high / low from settings - bounds.high = options.high || (options.high === 0 ? 0 : bounds.high); - bounds.low = options.low || (options.low === 0 ? 0 : bounds.low); + bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); + bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity @@ -285,9 +285,14 @@ Chartist.version = '0.2.4'; bounds.numberOfSteps = Math.round(bounds.range / bounds.step); // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace + // If we are already below the scaleMinSpace value we will scale up + var length = Chartist.projectLength(svg, bounds.step, bounds, options), + scaleUp = length < options.axisY.scaleMinSpace; + while (true) { - var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options); - if (length >= options.axisY.scaleMinSpace) { + if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { bounds.step /= 2; } else { break; From fae64714fd21269f1f21c86c03ddfeac4d2ad1bb Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Oct 2014 16:26:17 +0200 Subject: [PATCH 048/593] Refactored foreign object to accept attributes object instead of fixed params --- source/scripts/chartist.svg.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index fa0afe55..cbaf1f35 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -97,15 +97,12 @@ * * @memberof Chartist.Svg * @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 - * @param {String} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox - * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox - * @param {String} [width] The width of the foreignElement - * @param {String} [height] The height of the foreignElement + * @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. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child * @returns {Object} New wrapper object that wraps the foreignObject element */ - function foreignObject(content, x, y, width, height, className, parent, insertFirst) { + function foreignObject(content, attributes, className, parent, insertFirst) { // If content is string then we convert it to DOM // TODO: Handle case where content is not a string nor a DOM Node if(typeof content === 'string') { @@ -119,12 +116,7 @@ // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = Chartist.Svg('foreignObject', { - x: x, - y: y, - width: width, - height: height - }, className, parent, insertFirst); + var fnObj = parent.elem('foreignObject', attributes, className, insertFirst); // Add content to foreignObjectElement fnObj._node.appendChild(content); @@ -297,8 +289,8 @@ elem: function(name, attributes, className, insertFirst) { return Chartist.Svg(name, attributes, className, this, insertFirst); }, - foreignObject: function(content, x, y, width, height, className, insertFirst) { - return foreignObject(content, x, y, width, height, className, this, insertFirst); + foreignObject: function(content, attributes, className, insertFirst) { + return foreignObject(content, attributes, className, this, insertFirst); }, text: function(t) { text(this._node, t); From b7448e46764714d204e85cc983157b0ca3a60a5b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Oct 2014 16:26:41 +0200 Subject: [PATCH 049/593] Added styles for foreignObject labels --- source/styles/chartist.scss | 17 +++++++++++++++-- source/styles/settings/_chartist-settings.scss | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/source/styles/chartist.scss b/source/styles/chartist.scss index a31d95a6..a8cfc7c2 100644 --- a/source/styles/chartist.scss +++ b/source/styles/chartist.scss @@ -29,9 +29,14 @@ } } -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size) { +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align) { + display: block; + width: 100%; + height: 100%; fill: $ct-text-color; + color: $ct-text-color; font-size: $ct-text-size; + text-align: $ct-text-align; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { @@ -82,11 +87,19 @@ } } -@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { +@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { .#{$ct-class-label} { @include ct-chart-label($ct-text-color, $ct-text-size); } + .#{$ct-class-label}.#{$ct-class-horizontal} { + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align); + } + + .#{$ct-class-label}.#{$ct-class-vertical} { + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align); + } + .#{$ct-class-grid} { @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); } diff --git a/source/styles/settings/_chartist-settings.scss b/source/styles/settings/_chartist-settings.scss index 51f69d1d..059e3d8a 100644 --- a/source/styles/settings/_chartist-settings.scss +++ b/source/styles/settings/_chartist-settings.scss @@ -25,6 +25,9 @@ $ct-container-ratio: (1/1.618) !default; // Text styles for labels $ct-text-color: rgba(0, 0, 0, 0.4) !default; $ct-text-size: 0.75rem !default; +$ct-text-align: left !default; +$ct-horizontal-text-align: left !default; +$ct-vertical-text-align: right !default; // Grid styles $ct-grid-color: rgba(0, 0, 0, 0.2) !default; From 6d96a3145830dece416f4e233e1d1d74c1444831 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Oct 2014 17:25:15 +0200 Subject: [PATCH 050/593] Fixed chart rect calculations for very small charts --- source/scripts/chartist.core.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index d508eaa2..d19335f8 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -199,7 +199,7 @@ Chartist.version = '0.2.4'; * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return (Chartist.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset; + return Math.max((Chartist.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); }; /** @@ -351,10 +351,13 @@ Chartist.version = '0.2.4'; * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ Chartist.createChartRect = function (svg, options) { + var yOffset = options.axisY ? options.axisY.offset : 0, + xOffset = options.axisX ? options.axisX.offset : 0; + return { - x1: options.chartPadding + (options.axisY ? options.axisY.offset : 0), - y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - (options.axisX ? options.axisX.offset : 0), - x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, + x1: options.chartPadding + yOffset, + y1: Math.max((Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max((Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), y2: options.chartPadding, width: function () { return this.x2 - this.x1; From 253696cd333c4a2fe471a9b50c72ee9baaa23418 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 25 Oct 2014 15:02:37 +0200 Subject: [PATCH 051/593] Fixed outdated config values --- libdist/chartist.js | 19 ++++++++++--------- source/scripts/chartist.bar.js | 2 -- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libdist/chartist.js b/libdist/chartist.js index 9f951c7a..313265d4 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -216,7 +216,7 @@ * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return svg.height() - (options.chartPadding * 2) - options.axisX.offset; + return Math.max((Chartist.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); }; /** @@ -267,8 +267,8 @@ bounds = Chartist.getHighLow(normalizedData); // Overrides of high / low from settings - bounds.high = options.high || (options.high === 0 ? 0 : bounds.high); - bounds.low = options.low || (options.low === 0 ? 0 : bounds.low); + bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); + bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity @@ -394,15 +394,16 @@ * @memberof Chartist.Core * @param {Object} svg The svg element for the chart * @param {Object} options The Object that contains all the optional values for the chart - * @param {Number} xAxisOffset The offset of the x-axis to the border of the svg element - * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ - Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) { + Chartist.createChartRect = function (svg, options) { + var yOffset = options.axisY ? options.axisY.offset : 0, + xOffset = options.axisX ? options.axisX.offset : 0; + return { - x1: options.chartPadding + yAxisOffset, - y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset, - x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, + x1: options.chartPadding + yOffset, + y1: Math.max((Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max((Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), y2: options.chartPadding, width: function () { return this.x2 - this.x1; diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 9fec38d2..5494521f 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -40,8 +40,6 @@ label: 'ct-label', series: 'ct-series', bar: 'ct-bar', - thin: 'ct-thin', - thick: 'ct-thick', grid: 'ct-grid', vertical: 'ct-vertical', horizontal: 'ct-horizontal' From 106e3c59522d71d7b7ef5bef19f5bdf5f924b717 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 25 Oct 2014 15:05:10 +0200 Subject: [PATCH 052/593] Added feature detection for foreignObject and fallback for browser which do not support it --- source/scripts/chartist.bar.js | 41 +++++++++++++++++---------------- source/scripts/chartist.base.js | 4 +++- source/scripts/chartist.core.js | 38 ++++++++++++++++++++++-------- source/scripts/chartist.line.js | 26 +++++++++++++-------- source/scripts/chartist.svg.js | 11 +++++++++ 5 files changed, 80 insertions(+), 40 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 5494521f..b9c15eca 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -12,7 +12,7 @@ offset: 30, labelOffset: { x: 0, - y: 5 + y: 0 }, showLabel: true, showGrid: true, @@ -21,8 +21,8 @@ axisY: { offset: 40, labelOffset: { - x: -10, - y: -15 + x: 0, + y: 0 }, showLabel: true, showGrid: true, @@ -64,8 +64,8 @@ // Projected 0 point zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter); + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); // Draw the series // initialize series groups @@ -133,12 +133,17 @@ * @return {Object} An object which exposes the API for the created chart * * @example - * // These are the default options of the line chart + * // These are the default options of the bar chart * var options = { * // Options for X-Axis * axisX: { - * // The offset of the labels to the chart area - * offset: 10, + * // The offset of the chart drawing area to the border of the container + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not @@ -148,14 +153,17 @@ * }, * // Options for Y-Axis * axisY: { - * // The offset of the labels to the chart area - * offset: 15, + * // The offset of the chart drawing area to the border of the container + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not * showGrid: true, - * // For the Y-Axis you can set a label alignment property of right or left - * labelAlign: 'right', * // Interpolation function that allows you to intercept the value from the axis label * labelInterpolationFnc: function(value){return value;}, * // This value specifies the minimum height in pixel of the scale steps @@ -165,12 +173,6 @@ * width: undefined, * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') * height: undefined, - * // If the line should be drawn or not - * showLine: true, - * // If dots should be drawn or not - * showPoint: true, - * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) - * lineSmooth: true, * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value * low: undefined, * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value @@ -185,7 +187,6 @@ * label: 'ct-label', * series: 'ct-series', * bar: 'ct-bar', - * point: 'ct-point', * grid: 'ct-grid', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' @@ -215,7 +216,7 @@ * }, { * seriesBarDistance: 12, * low: -10, - * heigh: 10 + * high: 10 * }); * */ diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js index f57a140f..bbf21d45 100644 --- a/source/scripts/chartist.base.js +++ b/source/scripts/chartist.base.js @@ -69,6 +69,7 @@ this.options = options; this.responsiveOptions = responsiveOptions; this.eventEmitter = Chartist.EventEmitter(); + this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); window.addEventListener('resize', this.update.bind(this)); @@ -97,7 +98,8 @@ detach: detach, on: on, off: off, - version: Chartist.version + version: Chartist.version, + supportsForeignObject: false }); }(window, document, Chartist)); \ No newline at end of file diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index d19335f8..8dc01a90 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -368,9 +368,23 @@ Chartist.version = '0.2.4'; }; }; - Chartist.createLabel = function(parent, text, attributes, className) { - var content = '' + text + ''; - return parent.foreignObject(content, attributes); + /** + * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. + * + * @param {Object} parent The SVG element where the label should be created as a child + * @param {String} text The label text + * @param {Object} attributes An object with all attributes that should be set on the label element + * @param {String} className The class names that should be set for this element + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + * @returns {Object} The newly created SVG element + */ + Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { + if(supportsForeignObject) { + var content = '' + text + ''; + return parent.foreignObject(content, attributes); + } else { + return parent.elem('text', attributes, className).text(text); + } }; /** @@ -382,8 +396,10 @@ Chartist.version = '0.2.4'; * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) { + Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { // Create X-Axis data.labels.forEach(function (value, index) { var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), @@ -421,7 +437,7 @@ Chartist.version = '0.2.4'; if (options.axisX.showLabel) { var labelPosition = { x: pos + options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) }; var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { @@ -430,7 +446,7 @@ Chartist.version = '0.2.4'; width: width, height: height, style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.horizontal].join(' ')); + }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); eventEmitter.emit('draw', { type: 'label', @@ -462,8 +478,10 @@ Chartist.version = '0.2.4'; * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter) { + Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { // Create Y-Axis bounds.values.forEach(function (value, index) { var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), @@ -500,8 +518,8 @@ Chartist.version = '0.2.4'; if (options.axisY.showLabel) { var labelPosition = { - x: options.chartPadding + options.axisY.labelOffset.x, - y: pos + options.axisY.labelOffset.y + x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), + y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) }; var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { @@ -510,7 +528,7 @@ Chartist.version = '0.2.4'; width: width, height: height, style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.vertical].join(' ')); + }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); eventEmitter.emit('draw', { type: 'label', diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 9b8285a2..e9166c45 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -14,7 +14,7 @@ offset: 30, labelOffset: { x: 0, - y: 5 + y: 0 }, showLabel: true, showGrid: true, @@ -23,8 +23,8 @@ axisY: { offset: 40, labelOffset: { - x: -10, - y: -15 + x: 0, + y: 0 }, showLabel: true, showGrid: true, @@ -70,8 +70,8 @@ var labels = this.svg.elem('g'), grid = this.svg.elem('g'); - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter); + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); // Draw the series // initialize series groups @@ -191,7 +191,12 @@ * // Options for X-Axis * axisX: { * // The offset of the labels to the chart area - * offset: 10, + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not @@ -202,13 +207,16 @@ * // Options for Y-Axis * axisY: { * // The offset of the labels to the chart area - * offset: 15, + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not * showGrid: true, - * // For the Y-Axis you can set a label alignment property of right or left - * labelAlign: 'right', * // Interpolation function that allows you to intercept the value from the axis label * labelInterpolationFnc: function(value){return value;}, * // This value specifies the minimum height in pixel of the scale steps diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index cbaf1f35..3752f0da 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -320,4 +320,15 @@ }; }; + /** + * 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. + * + * @memberof Chartist.Svg + * @param {String} feature The SVG 1.1 feature that should be checked for support. + * @returns {Boolean} True of false if the feature is supported or not + */ + Chartist.Svg.isSupported = function(feature) { + return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); + }; + }(window, document, Chartist)); \ No newline at end of file From 83deda4d9d7323d2e733f6128b6c996e7883e242 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 25 Oct 2014 15:05:42 +0200 Subject: [PATCH 053/593] Fixed base chart api documentation --- source/scripts/chartist.base.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js index bbf21d45..6d0206e9 100644 --- a/source/scripts/chartist.base.js +++ b/source/scripts/chartist.base.js @@ -1,5 +1,5 @@ /** - * Base for all chart classes. + * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. * * @module Chartist.Base */ @@ -16,7 +16,7 @@ /** * Updates the chart which currently does a full reconstruction of the SVG DOM * - * @memberof Chartist.Line + * @memberof Chartist.Base */ function update() { this.createChart(this.optionsProvider.currentOptions); @@ -25,7 +25,7 @@ /** * 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. * - * @memberof Chartist.Line + * @memberof Chartist.Base */ function detach() { window.removeEventListener('resize', this.update); @@ -35,7 +35,7 @@ /** * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * - * @memberof Chartist.Line + * @memberof Chartist.Base * @param {String} event Name of the event. Check the examples for supported events. * @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. */ @@ -46,7 +46,7 @@ /** * 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. * - * @memberof Chartist.Line + * @memberof Chartist.Base * @param {String} event Name of the event for which a handler should be removed * @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. */ From 06c7f15a1488272e0812f5b06966bd03a31e62a0 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 25 Oct 2014 15:06:49 +0200 Subject: [PATCH 054/593] Added new example for multiline text --- source/site/data/pages/examples.yml | 10 ++++++++++ source/site/examples/example-multiline-bar.js | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 source/site/examples/example-multiline-bar.js diff --git a/source/site/data/pages/examples.yml b/source/site/data/pages/examples.yml index e65b8f7b..94ce92f0 100644 --- a/source/site/data/pages/examples.yml +++ b/source/site/data/pages/examples.yml @@ -90,6 +90,16 @@ sections: classes: ct-golden-section intro: > With the help of draw events we are able to add a custom SVG shape to the peek of our bars. + - type: live-example + data: + title: Multi-line labels + level: 4 + id: example-multiline-bar + classes: ct-golden-section + intro: > + Chartist will figure out if your browser supports foreignObject and it will use them to create labels + that re based on regular HTML text elements. Multi-line and regular CSS styles are just two of many + benefits while using foreignObjects! - title: Pie chart examples level: 3 items: diff --git a/source/site/examples/example-multiline-bar.js b/source/site/examples/example-multiline-bar.js new file mode 100644 index 00000000..e71f1642 --- /dev/null +++ b/source/site/examples/example-multiline-bar.js @@ -0,0 +1,20 @@ +new Chartist.Bar('.ct-chart', { + labels: ['First quarter of the year', 'Second quarter of the year', 'Third quarter of the year', 'Fourth quarter of the year'], + series: [ + [60000, 40000, 80000, 70000], + [40000, 30000, 70000, 65000], + [8000, 3000, 10000, 6000] + ] +}, { + seriesBarDistance: 10, + axisX: { + offset: 60 + }, + axisY: { + offset: 80, + labelInterpolationFnc: function(value) { + return value + ' CHF' + }, + scaleMinSpace: 15 + } +}); \ No newline at end of file From f606c144682d74284b2a65bef4749907a95b95a1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 25 Oct 2014 16:27:39 +0200 Subject: [PATCH 055/593] Added number conversion for possible string data values, fixes #72 --- source/scripts/chartist.core.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 8dc01a90..167bb7c3 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -137,6 +137,11 @@ Chartist.version = '0.2.4'; // otherwise the value directly (array or number) array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; + + // Convert values to number + for (var j = 0; j < array[i].length; j++) { + array[i][j] = +array[i][j]; + } } return array; From 9170d4fd4cb6cf8d69d65ba487c8d3287819b65d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 25 Oct 2014 23:31:05 +0200 Subject: [PATCH 056/593] Added browser support table, fixes #67 --- source/site/data/pages/index.yml | 158 ++++++++++++++++++ .../site/partials/browser-support-table.hbs | 22 +++ source/styles/site/_landing.scss | 87 ++++++++++ .../styles/site/settings/_chartist-docs.scss | 1 + 4 files changed, 268 insertions(+) create mode 100644 source/site/partials/browser-support-table.hbs diff --git a/source/site/data/pages/index.yml b/source/site/data/pages/index.yml index 8716e7ec..c55a8224 100644 --- a/source/site/data/pages/index.yml +++ b/source/site/data/pages/index.yml @@ -9,6 +9,164 @@ gallery-examples: classes: ct-golden-section sections: + - title: Browser compatibility + level: 4 + items: + - type: browser-support-table + data: + browsers: + - IE9 + - IE10 + - IE11 + - Firefox 31 + - Chrome 35 + - Safari 7 + - Safari 8 + - Andorid 4.3 + - Andorid 4.4 + - iOS Safari 6 + - iOS Safari 7 + features: + - name: Overall Browser Support + browsers: + - name: IE9 + status: supported + text: Supported + - name: IE10 + status: supported + text: Supported + - name: IE11 + status: supported + text: Supported + - name: Firefox 31 + status: supported + text: Supported + - name: Chrome 35 + status: supported + text: Supported + - name: Safari 7 + status: supported + text: Supported + - name: Safari 8 + status: supported + text: Supported + - name: Andorid 4.3 + status: supported + text: Supported + - name: Andorid 4.4 + status: supported + text: Supported + - name: iOS Safari 6 + status: supported + text: Supported + - name: iOS Safari 7 + status: supported + text: Supported + - name: Multi-line Labels (foreignObject) + browsers: + - name: IE9 + status: not-supported + text: Not supported + - name: IE10 + status: not-supported + text: Not supported + - name: IE11 + status: not-supported + text: Not supported + - name: Firefox 31 + status: supported + text: Supported + - name: Chrome 35 + status: supported + text: Supported + - name: Safari 7 + status: not-supported + text: Not supported + - name: Safari 8 + status: supported + text: Supported + - name: Andorid 4.3 + status: not-supported + text: Not supported + - name: Andorid 4.4 + status: supported + text: Supported + - name: iOS Safari 6 + status: not-supported + text: Not supported + - name: iOS Safari 7 + status: supported + text: Supported + - name: Advanced CSS Animations + browsers: + - name: IE9 + status: not-supported + text: Not supported + - name: IE10 + status: not-supported + text: Not supported + - name: IE11 + status: not-supported + text: Not supported + - name: Firefox 31 + status: supported + text: Supported + - name: Chrome 35 + status: supported + text: Supported + - name: Safari 7 + status: not-supported + text: Not supported + - name: Safari 8 + status: supported + text: Supported + - name: Andorid 4.3 + status: not-supported + text: Not supported + - name: Andorid 4.4 + status: supported + text: Supported + - name: iOS Safari 6 + status: supported + text: Supported + - name: iOS Safari 7 + status: supported + text: Supported + - name: Reponsive Options Override + browsers: + - name: IE9* + status: supported + text: Supported with polyfill + - name: IE10 + status: supported + text: Supported + - name: IE11 + status: supported + text: Supported + - name: Firefox 31 + status: supported + text: Supported + - name: Chrome 35 + status: supported + text: Supported + - name: Safari 7 + status: supported + text: Supported + - name: Safari 8 + status: supported + text: Supported + - name: Andorid 4.3 + status: supported + text: Supported + - name: Andorid 4.4 + status: supported + text: Supported + - name: iOS Safari 6 + status: supported + text: Supported + - name: iOS Safari 7 + status: supported + text: Supported - title: Chart CSS animation example level: 3 items: diff --git a/source/site/partials/browser-support-table.hbs b/source/site/partials/browser-support-table.hbs new file mode 100644 index 00000000..89582358 --- /dev/null +++ b/source/site/partials/browser-support-table.hbs @@ -0,0 +1,22 @@ + + + + + {{#each browsers}} + + {{/each}} + + + + {{#each features}} + + + {{#each browsers}} + + {{/each}} + + {{/each}} + +
    {{this}}
    {{name}} + {{text}} +
    \ No newline at end of file diff --git a/source/styles/site/_landing.scss b/source/styles/site/_landing.scss index d8e8ad20..79ec077d 100644 --- a/source/styles/site/_landing.scss +++ b/source/styles/site/_landing.scss @@ -82,4 +82,91 @@ } } } +} + +.brwsrsup { + text-align: center; + + .brwsrsup__support--supported { + color: $color-green; + @include icon($fa-var-check-circle, $icon-location: after, $icon-size: 1.5rem); + } + + .brwsrsup__visually-hidden { + position: absolute; + overflow: hidden; + clip: rect(0 0 0 0); + height: 1px; + width: 1px; + margin: -1px; + padding: 0; + border: 0; + } +} + +@media screen and (max-width: 1100px) { + .brwsrsup { + display: block; + text-align: left; + + thead { + display: none; + } + + .brwsrsup__feature { + display: block; + padding: 10px 0; + margin: 20px 0 10px 0; + } + + tbody { + display: block; + } + + tr { + display: block; + &:after { + content: ""; + display: table; + clear: both; + } + } + + td { + display: block; + } + + .brwsrsup__support { + diplay: block; + padding: 5px; + width: auto; + float: left; + margin: 0 10px 10px 0; + + &:before { + content: attr(data-browser)" "; + } + } + + .brwsrsup__support--supported { + background: $color-green; + color: white; + + &:before { + content: attr(data-browser)" "; + } + + @include icon($fa-var-check-circle, $icon-location: after); + } + + .brwsrsup__support--not-supported { + background: $color-red; + color: lighten($color-white, 10%); + + &:before { + content: attr(data-browser)" "; + } + @include icon($fa-var-exclamation-circle, $icon-location: after); + } + } } \ No newline at end of file diff --git a/source/styles/site/settings/_chartist-docs.scss b/source/styles/site/settings/_chartist-docs.scss index 05a2fdb0..c5a56b4f 100644 --- a/source/styles/site/settings/_chartist-docs.scss +++ b/source/styles/site/settings/_chartist-docs.scss @@ -1,6 +1,7 @@ $color-white: #EADBC4; $color-grapefruit: #F05B4F; $color-red: #D70206; +$color-green: #67bf26; $color-yellow: #F4C63D; $color-gray: #453D3F; $color-black: $color-gray; From cb40e89f3b781f17528184448454f76ec97827f1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 25 Oct 2014 23:33:40 +0200 Subject: [PATCH 057/593] Version bump --- bower.json | 2 +- package.json | 2 +- source/scripts/chartist.core.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index e1165db1..a27796e1 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.2.4", + "version": "0.3.0", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/package.json b/package.json index dc6e1888..5b270c65 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.2.4", + "version": "0.3.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 167bb7c3..476e2da9 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = {}; -Chartist.version = '0.2.4'; +Chartist.version = '0.3.0'; (function (window, document, Chartist) { 'use strict'; From f3741eef14af98d8fd9a49f75356a2d4d81d29b6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 28 Oct 2014 13:20:59 +0100 Subject: [PATCH 058/593] Fixed libdist error with version bump to 0.3.1 --- bower.json | 2 +- libdist/chartist.js | 341 +++++++++--------- libdist/chartist.min.css | 4 +- libdist/chartist.min.js | 4 +- libdist/chartist.min.map | 2 +- libdist/scss/chartist.scss | 17 +- libdist/scss/settings/_chartist-settings.scss | 3 + package.json | 2 +- source/scripts/chartist.core.js | 2 +- 9 files changed, 190 insertions(+), 187 deletions(-) diff --git a/bower.json b/bower.json index a27796e1..63408aea 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.3.0", + "version": "0.3.1", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index 313265d4..9ab8810c 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.2.4 + /* Chartist.js 0.3.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -21,7 +21,7 @@ * @module Chartist.Core */ var Chartist = {}; - Chartist.version = '0.2.4'; + Chartist.version = '0.3.1'; (function (window, document, Chartist) { 'use strict'; @@ -154,6 +154,11 @@ // otherwise the value directly (array or number) array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; + + // Convert values to number + for (var j = 0; j < array[i].length; j++) { + array[i][j] = +array[i][j]; + } } return array; @@ -302,9 +307,14 @@ bounds.numberOfSteps = Math.round(bounds.range / bounds.step); // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace + // If we are already below the scaleMinSpace value we will scale up + var length = Chartist.projectLength(svg, bounds.step, bounds, options), + scaleUp = length < options.axisY.scaleMinSpace; + while (true) { - var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options); - if (length >= options.axisY.scaleMinSpace) { + if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { bounds.step /= 2; } else { break; @@ -335,40 +345,6 @@ return bounds; }; - /** - * Calculate the needed offset to fit in the labels - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Object} labelClass All css classes of the label - * @param {Function} labelInterpolationFnc The function that interpolates the label value - * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length - * @return {Number} The number that represents the label offset in pixels - */ - Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) { - var offset = 0; - for (var i = 0; i < data.length; i++) { - // If interpolation function returns falsy value we skipp this label - var interpolated = labelInterpolationFnc(data[i], i); - if (!interpolated && interpolated !== 0) { - continue; - } - - var label = svg.elem('text', { - dx: 0, - dy: 0 - }, labelClass).text('' + interpolated); - - // Check if this is the largest label and update offset - offset = Math.max(offset, label[offsetFnc]()); - // Remove label after offset Calculation - label.remove(); - } - - return offset; - }; - /** * Calculate cartesian coordinates of polar coordinates * @@ -414,6 +390,25 @@ }; }; + /** + * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. + * + * @param {Object} parent The SVG element where the label should be created as a child + * @param {String} text The label text + * @param {Object} attributes An object with all attributes that should be set on the label element + * @param {String} className The class names that should be set for this element + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + * @returns {Object} The newly created SVG element + */ + Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { + if(supportsForeignObject) { + var content = '' + text + ''; + return parent.foreignObject(content, attributes); + } else { + return parent.elem('text', attributes, className).text(text); + } + }; + /** * Generate grid lines and labels for the x-axis into grid and labels group SVG elements * @@ -423,13 +418,16 @@ * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) { + Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { // Create X-Axis data.labels.forEach(function (value, index) { var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - space = chartRect.width() / data.labels.length, - pos = chartRect.x1 + space * index; + width = chartRect.width() / data.labels.length, + height = options.axisX.offset, + pos = chartRect.x1 + width * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -459,21 +457,18 @@ } if (options.axisX.showLabel) { - // Use config offset for setting labels of - var labelPos = { - x: pos + 2, - y: 0 + var labelPosition = { + x: pos + options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) }; - var labelElement = labels.elem('text', { - dx: labelPos.x - }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue); - - // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos - labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset; - labelElement.attr({ - dy: labelPos.y - }); + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); eventEmitter.emit('draw', { type: 'label', @@ -482,9 +477,15 @@ group: labels, element: labelElement, text: '' + interpolatedValue, - x: labelPos.x, - y: labelPos.y, - space: space + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.width; + } }); } }); @@ -498,15 +499,17 @@ * @param {Object} bounds All the values to set the bounds of the chart * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Number} offset Offset for the y-axis * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) { + Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { // Create Y-Axis bounds.values.forEach(function (value, index) { var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - space = chartRect.height() / bounds.values.length, - pos = chartRect.y1 - space * index; + width = options.axisY.offset, + height = chartRect.height() / bounds.values.length, + pos = chartRect.y1 - height * index; // If interpolated value returns falsey (except 0) we don't draw the grid line if (!interpolatedValue && interpolatedValue !== 0) { @@ -536,18 +539,18 @@ } if (options.axisY.showLabel) { - // Use calculated offset and include padding for label x position - // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier - var labelPos = { - x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, - y: pos - 2 + var labelPosition = { + x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), + y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) }; - var labelElement = labels.elem('text', { - dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding, - dy: pos - 2, - 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start' - }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue); + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); eventEmitter.emit('draw', { type: 'label', @@ -556,9 +559,15 @@ group: labels, element: labelElement, text: '' + interpolatedValue, - x: labelPos.x, - y: labelPos.y, - space: space + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.height; + } }); } }); @@ -974,7 +983,7 @@ }; }(window, document, Chartist));;/** - * Base for all chart classes. + * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. * * @module Chartist.Base */ @@ -991,7 +1000,7 @@ /** * Updates the chart which currently does a full reconstruction of the SVG DOM * - * @memberof Chartist.Line + * @memberof Chartist.Base */ function update() { this.createChart(this.optionsProvider.currentOptions); @@ -1000,7 +1009,7 @@ /** * 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. * - * @memberof Chartist.Line + * @memberof Chartist.Base */ function detach() { window.removeEventListener('resize', this.update); @@ -1010,7 +1019,7 @@ /** * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * - * @memberof Chartist.Line + * @memberof Chartist.Base * @param {String} event Name of the event. Check the examples for supported events. * @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. */ @@ -1021,7 +1030,7 @@ /** * 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. * - * @memberof Chartist.Line + * @memberof Chartist.Base * @param {String} event Name of the event for which a handler should be removed * @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. */ @@ -1044,6 +1053,7 @@ this.options = options; this.responsiveOptions = responsiveOptions; this.eventEmitter = Chartist.EventEmitter(); + this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); window.addEventListener('resize', this.update.bind(this)); @@ -1072,7 +1082,8 @@ detach: detach, on: on, off: off, - version: Chartist.version + version: Chartist.version, + supportsForeignObject: false }); }(window, document, Chartist));;/** @@ -1174,15 +1185,12 @@ * * @memberof Chartist.Svg * @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 - * @param {String} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox - * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox - * @param {String} [width] The width of the foreignElement - * @param {String} [height] The height of the foreignElement + * @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. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child * @returns {Object} New wrapper object that wraps the foreignObject element */ - function foreignObject(content, x, y, width, height, className, parent, insertFirst) { + function foreignObject(content, attributes, className, parent, insertFirst) { // If content is string then we convert it to DOM // TODO: Handle case where content is not a string nor a DOM Node if(typeof content === 'string') { @@ -1196,12 +1204,7 @@ // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = Chartist.Svg('foreignObject', { - x: x, - y: y, - width: width, - height: height - }, className, parent, insertFirst); + var fnObj = parent.elem('foreignObject', attributes, className, insertFirst); // Add content to foreignObjectElement fnObj._node.appendChild(content); @@ -1374,8 +1377,8 @@ elem: function(name, attributes, className, insertFirst) { return Chartist.Svg(name, attributes, className, this, insertFirst); }, - foreignObject: function(content, x, y, width, height, className, insertFirst) { - return foreignObject(content, x, y, width, height, className, this, insertFirst); + foreignObject: function(content, attributes, className, insertFirst) { + return foreignObject(content, attributes, className, this, insertFirst); }, text: function(t) { text(this._node, t); @@ -1405,6 +1408,17 @@ }; }; + /** + * 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. + * + * @memberof Chartist.Svg + * @param {String} feature The SVG 1.1 feature that should be checked for support. + * @returns {Boolean} True of false if the feature is supported or not + */ + Chartist.Svg.isSupported = function(feature) { + return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); + }; + }(window, document, Chartist));;/** * 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. * @@ -1418,16 +1432,23 @@ var defaultOptions = { axisX: { - offset: 10, + offset: 30, + labelOffset: { + x: 0, + y: 0 + }, showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop }, axisY: { - offset: 15, + offset: 40, + labelOffset: { + x: 0, + y: 0 + }, showLabel: true, showGrid: true, - labelAlign: 'right', labelInterpolationFnc: Chartist.noop, scaleMinSpace: 30 }, @@ -1455,9 +1476,7 @@ }; function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], + var seriesGroups = [], bounds, normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); @@ -1467,35 +1486,13 @@ // initialize bounds bounds = Chartist.getBounds(this.svg, normalizedData, options); - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - this.svg, - this.data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } - - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - this.svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } - - var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing var labels = this.svg.elem('g'), grid = this.svg.elem('g'); - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); // Draw the series // initialize series groups @@ -1615,7 +1612,12 @@ * // Options for X-Axis * axisX: { * // The offset of the labels to the chart area - * offset: 10, + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not @@ -1626,13 +1628,16 @@ * // Options for Y-Axis * axisY: { * // The offset of the labels to the chart area - * offset: 15, + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not * showGrid: true, - * // For the Y-Axis you can set a label alignment property of right or left - * labelAlign: 'right', * // Interpolation function that allows you to intercept the value from the axis label * labelInterpolationFnc: function(value){return value;}, * // This value specifies the minimum height in pixel of the scale steps @@ -1755,18 +1760,25 @@ var defaultOptions = { axisX: { - offset: 10, + offset: 30, + labelOffset: { + x: 0, + y: 0 + }, showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop }, axisY: { - offset: 15, + offset: 40, + labelOffset: { + x: 0, + y: 0 + }, showLabel: true, showGrid: true, - labelAlign: 'right', labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 40 + scaleMinSpace: 30 }, width: undefined, height: undefined, @@ -1779,8 +1791,6 @@ label: 'ct-label', series: 'ct-series', bar: 'ct-bar', - thin: 'ct-thin', - thick: 'ct-thick', grid: 'ct-grid', vertical: 'ct-vertical', horizontal: 'ct-horizontal' @@ -1788,9 +1798,7 @@ }; function createChart(options) { - var xAxisOffset, - yAxisOffset, - seriesGroups = [], + var seriesGroups = [], bounds, normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); @@ -1800,37 +1808,15 @@ // initialize bounds bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); - xAxisOffset = options.axisX.offset; - if (options.axisX.showLabel) { - xAxisOffset += Chartist.calculateLabelOffset( - this.svg, - this.data.labels, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisX.labelInterpolationFnc, - 'height' - ); - } - - yAxisOffset = options.axisY.offset; - if (options.axisY.showLabel) { - yAxisOffset += Chartist.calculateLabelOffset( - this.svg, - bounds.values, - [options.classNames.label, options.classNames.horizontal].join(' '), - options.axisY.labelInterpolationFnc, - 'width' - ); - } - - var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset); + var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing var labels = this.svg.elem('g'), grid = this.svg.elem('g'), // Projected 0 point zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter); - Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter); + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); // Draw the series // initialize series groups @@ -1898,12 +1884,17 @@ * @return {Object} An object which exposes the API for the created chart * * @example - * // These are the default options of the line chart + * // These are the default options of the bar chart * var options = { * // Options for X-Axis * axisX: { - * // The offset of the labels to the chart area - * offset: 10, + * // The offset of the chart drawing area to the border of the container + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not @@ -1913,14 +1904,17 @@ * }, * // Options for Y-Axis * axisY: { - * // The offset of the labels to the chart area - * offset: 15, + * // The offset of the chart drawing area to the border of the container + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, * // If labels should be shown or not * showLabel: true, * // If the axis grid should be drawn or not * showGrid: true, - * // For the Y-Axis you can set a label alignment property of right or left - * labelAlign: 'right', * // Interpolation function that allows you to intercept the value from the axis label * labelInterpolationFnc: function(value){return value;}, * // This value specifies the minimum height in pixel of the scale steps @@ -1930,12 +1924,6 @@ * width: undefined, * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') * height: undefined, - * // If the line should be drawn or not - * showLine: true, - * // If dots should be drawn or not - * showPoint: true, - * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) - * lineSmooth: true, * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value * low: undefined, * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value @@ -1950,7 +1938,6 @@ * label: 'ct-label', * series: 'ct-series', * bar: 'ct-bar', - * point: 'ct-point', * grid: 'ct-grid', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' @@ -1980,7 +1967,7 @@ * }, { * seriesBarDistance: 12, * low: -10, - * heigh: 10 + * high: 10 * }); * */ diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index 1939712b..dd341785 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,7 +1,7 @@ -/* Chartist.js 0.2.4 +/* Chartist.js 0.3.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -.ct-chart .ct-label{fill:rgba(0,0,0,.4);font-size:.75rem}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file +.ct-chart .ct-label,.ct-chart .ct-label.ct-horizontal{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:left}.ct-chart .ct-label.ct-vertical{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:right}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 57ff58b7..0167b46f 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.2.4 +/* Chartist.js 0.3.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.2.4",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return a.height()-2*b.chartPadding-b.axisX.offset},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},c.calculateLabelOffset=function(a,b,c,d,e){for(var f=0,g=0;gd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var q=c.catmullRom2bezier(n),r=0;ra.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.3.1",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.getPixelLength(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.getPixelLength(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.getPixelLength(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;jd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 0f33e73d..6fce0ca2 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","normalizeDataArray","dataArray","j","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","max","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","axisY","scaleMinSpace","values","push","calculateLabelOffset","labelClass","labelInterpolationFnc","offsetFnc","interpolated","label","elem","dx","dy","text","remove","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","xAxisOffset","yAxisOffset","x1","y1","x2","y2","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","space","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPos","labelElement","createYAxis","vertical","labelAlign","text-anchor","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24464,"pos":24450,"col":12,"line":641,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":24464,"pos":24450,"col":12,"line":641,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","on","off","Base","addEventListener","bind","setTimeout","xmlNs","qualifiedName","prefix","uri","name","attributes","parent","insertFirst","node","ns","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","foreignObject","content","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","thin","thick","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","labelOffset","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","labelPosition","labelDirection","Pie","labelOverflow"],"mappings":";;;;;;CAAC,SAASA,EAAMC,GACU,gBAAZC,SACNC,OAAOD,QAAUD,IAEK,kBAAXG,SAAyBA,OAAOC,IAC3CD,UAAWH,GAGXD,EAAe,SAAIC,KAEzBK,KAAM,WAYN,GAAIC,KAytEJ,OAxtEAA,GAASC,QAAU,QAElB,SAAUC,EAAQC,EAAUH,GAC3B,YASAA,GAASI,KAAO,SAAUC,GACxB,MAAOA,IAUTL,EAASM,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAYtCL,EAASS,OAAS,SAAUC,EAAQC,GAClCD,EAASA,KACT,KAAK,GAAIE,KAAQD,GAEbD,EAAOE,GADmB,gBAAjBD,GAAOC,GACDZ,EAASS,OAAOC,EAAOE,GAAOD,EAAOC,IAErCD,EAAOC,EAG1B,OAAOF,IASTV,EAASa,eAAiB,SAASC,GAKjC,MAJqB,gBAAXA,KACRA,EAASA,EAAOC,QAAQ,MAAO,MAGzBD,GAUVd,EAASgB,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQd,EAASa,cAAcC,IAahEjB,EAASmB,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIC,EA8BJ,OA5BAH,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAGWG,SAA1BL,EAAUM,aACZF,EAAMJ,EAAUM,YAAYC,MAC1BN,MAAOA,EACPC,OAAQA,IACPM,mBAAmBC,SAASN,GAAWI,MACxCG,MAAO,UAAYT,EAAQ,aAAeC,EAAS,MAGrDE,EAAIO,UAIJP,EAAMxB,EAASgC,IAAI,OAAOL,MACxBN,MAAOA,EACPC,OAAQA,IACPO,SAASN,GAAWI,MACrBG,MAAO,UAAYT,EAAQ,aAAeC,EAAS,MAIrDF,EAAUa,YAAYT,EAAIU,OAC1Bd,EAAUM,YAAcF,GAGnBA,GAUTxB,EAASmC,aAAe,SAAUC,GAGhC,IAAK,GAFDC,MAEKC,EAAI,EAAGA,EAAIF,EAAKG,OAAOzB,OAAQwB,IAGtCD,EAAMC,GAAgC,gBAApBF,GAAKG,OAAOD,IAA4Cb,SAAxBW,EAAKG,OAAOD,GAAGF,KAC/DA,EAAKG,OAAOD,GAAGF,KAAOA,EAAKG,OAAOD,EAGtC,OAAOD,IAWTrC,EAASwC,mBAAqB,SAAUC,EAAW3B,GACjD,IAAK,GAAIwB,GAAI,EAAGA,EAAIG,EAAU3B,OAAQwB,IACpC,GAAIG,EAAUH,GAAGxB,SAAWA,EAI5B,IAAK,GAAI4B,GAAID,EAAUH,GAAGxB,OAAYA,EAAJ4B,EAAYA,IAC5CD,EAAUH,GAAGI,GAAK,CAItB,OAAOD,IAUTzC,EAAS2C,iBAAmB,SAAUC,GACpC,MAAOC,MAAKC,MAAMD,KAAKE,IAAIF,KAAKG,IAAIJ,IAAUC,KAAKI,OAarDjD,EAASkD,cAAgB,SAAU1B,EAAKV,EAAQqC,EAAQC,GACtD,GAAIC,GAAkBrD,EAASsD,mBAAmB9B,EAAK4B,EACvD,OAAQtC,GAASqC,EAAOI,MAAQF,GAWlCrD,EAASsD,mBAAqB,SAAU9B,EAAK4B,GAC3C,MAAO5B,GAAIF,SAAmC,EAAvB8B,EAAQI,aAAoBJ,EAAQK,MAAMC,QAUnE1D,EAAS2D,WAAa,SAAUlB,GAC9B,GAAIH,GACFI,EACAkB,GACEC,MAAOC,OAAOC,UACdC,IAAKF,OAAOC,UAGhB,KAAKzB,EAAI,EAAGA,EAAIG,EAAU3B,OAAQwB,IAChC,IAAKI,EAAI,EAAGA,EAAID,EAAUH,GAAGxB,OAAQ4B,IAC/BD,EAAUH,GAAGI,GAAKkB,EAAQC,OAC5BD,EAAQC,KAAOpB,EAAUH,GAAGI,IAG1BD,EAAUH,GAAGI,GAAKkB,EAAQI,MAC5BJ,EAAQI,IAAMvB,EAAUH,GAAGI,GAKjC,OAAOkB,IAcT5D,EAASiE,UAAY,SAAUzC,EAAK0C,EAAgBd,EAASe,GAC3D,GAAI7B,GACF8B,EACAC,EACAlB,EAASnD,EAAS2D,WAAWO,EAsC/B,KAnCAf,EAAOU,KAAOT,EAAQS,OAA0B,IAAjBT,EAAQS,KAAa,EAAIV,EAAOU,MAC/DV,EAAOa,IAAMZ,EAAQY,MAAwB,IAAhBZ,EAAQY,IAAY,EAAIb,EAAOa,KAIzDb,EAAOU,OAASV,EAAOa,MAEN,IAAfb,EAAOa,IACRb,EAAOU,KAAO,EACNV,EAAOa,IAAM,EAErBb,EAAOU,KAAO,EAGdV,EAAOa,IAAM,IAObG,GAAqC,IAAnBA,KACpBhB,EAAOU,KAAOhB,KAAKyB,IAAIH,EAAgBhB,EAAOU,MAC9CV,EAAOa,IAAMnB,KAAK0B,IAAIJ,EAAgBhB,EAAOa,MAG/Cb,EAAOqB,WAAarB,EAAOU,KAAOV,EAAOa,IACzCb,EAAOsB,IAAMzE,EAAS2C,iBAAiBQ,EAAOqB,YAC9CrB,EAAOoB,IAAM1B,KAAKC,MAAMK,EAAOa,IAAMnB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOmB,IAAMzB,KAAK8B,KAAKxB,EAAOU,KAAOhB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOI,MAAQJ,EAAOmB,IAAMnB,EAAOoB,IACnCpB,EAAOyB,KAAO/B,KAAK6B,IAAI,GAAIvB,EAAOsB,KAClCtB,EAAO0B,cAAgBhC,KAAKiC,MAAM3B,EAAOI,MAAQJ,EAAOyB,QAG3C,CACX,GAAI9D,GAASd,EAASkD,cAAc1B,EAAK2B,EAAOyB,KAAO,EAAGzB,EAAQC,EAClE,MAAItC,GAAUsC,EAAQ2B,MAAMC,eAG1B,KAFA7B,GAAOyB,MAAQ,EASnB,IAFAR,EAASjB,EAAOoB,IAChBF,EAASlB,EAAOmB,IACXhC,EAAIa,EAAOoB,IAAKjC,GAAKa,EAAOmB,IAAKhC,GAAKa,EAAOyB,KAC5CtC,EAAIa,EAAOyB,KAAOzB,EAAOa,MAC3BI,GAAUjB,EAAOyB,MAGftC,EAAIa,EAAOyB,KAAOzB,EAAOU,OAC3BQ,GAAUlB,EAAOyB,KAQrB,KALAzB,EAAOoB,IAAMH,EACbjB,EAAOmB,IAAMD,EACblB,EAAOI,MAAQJ,EAAOmB,IAAMnB,EAAOoB,IAEnCpB,EAAO8B,UACF3C,EAAIa,EAAOoB,IAAKjC,GAAKa,EAAOmB,IAAKhC,GAAKa,EAAOyB,KAChDzB,EAAO8B,OAAOC,KAAK5C,EAGrB,OAAOa,IAcTnD,EAASmF,qBAAuB,SAAU3D,EAAKY,EAAMgD,EAAYC,EAAuBC,GAEtF,IAAK,GADD5B,GAAS,EACJpB,EAAI,EAAGA,EAAIF,EAAKtB,OAAQwB,IAAK,CAEpC,GAAIiD,GAAeF,EAAsBjD,EAAKE,GAAIA,EAClD,IAAKiD,GAAiC,IAAjBA,EAArB,CAIA,GAAIC,GAAQhE,EAAIiE,KAAK,QACnBC,GAAI,EACJC,GAAI,GACHP,GAAYQ,KAAK,GAAKL,EAGzB7B,GAASb,KAAKyB,IAAIZ,EAAQ8B,EAAMF,MAEhCE,EAAMK,UAGR,MAAOnC,IAaT1D,EAAS8F,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAMrD,KAAKuD,GAAK,GAEvD,QACEC,EAAGN,EAAWE,EAASpD,KAAKyD,IAAIH,GAChCI,EAAGP,EAAWC,EAASpD,KAAK2D,IAAIL,KAcpCnG,EAASyG,gBAAkB,SAAUjF,EAAK4B,EAASsD,EAAaC,GAC9D,OACEC,GAAIxD,EAAQI,aAAemD,EAC3BE,IAAK7G,EAASa,eAAeuC,EAAQ9B,SAAWE,EAAIF,UAAY8B,EAAQI,aAAekD,EACvFI,IAAK9G,EAASa,eAAeuC,EAAQ/B,QAAUG,EAAIH,SAAW+B,EAAQI,aACtEuD,GAAI3D,EAAQI,aACZnC,MAAO,WACL,MAAOtB,MAAK+G,GAAK/G,KAAK6G,IAExBtF,OAAQ,WACN,MAAOvB,MAAK8G,GAAK9G,KAAKgH,MAe5B/G,EAASgH,YAAc,SAAUC,EAAW7E,EAAM8E,EAAMC,EAAQ/D,EAASgE,GAEvEhF,EAAK+E,OAAOE,QAAQ,SAAUzE,EAAO0E,GACnC,GAAIC,GAAoBnE,EAAQK,MAAM4B,sBAAsBzC,EAAO0E,GACjEE,EAAQP,EAAU5F,QAAUe,EAAK+E,OAAOrG,OACxC2G,EAAMR,EAAUL,GAAKY,EAAQF,CAG/B,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAInE,EAAQK,MAAMiE,SAAU,CAC1B,GAAIC,GAAcT,EAAKzB,KAAK,QAC1BmB,GAAIa,EACJZ,GAAII,EAAUJ,GACdC,GAAIW,EACJV,GAAIE,EAAUF,KACZ3D,EAAQwE,WAAWV,KAAM9D,EAAQwE,WAAWC,YAAYC,KAAK,KAGjEV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTf,GAAIa,EACJZ,GAAII,EAAUJ,GACdC,GAAIW,EACJV,GAAIE,EAAUF,KAIlB,GAAI3D,EAAQK,MAAM2E,UAAW,CAE3B,GAAIC,IACFhC,EAAGoB,EAAM,EACTlB,EAAG,GAGD+B,EAAenB,EAAO1B,KAAK,QAC7BC,GAAI2C,EAAShC,IACXjD,EAAQwE,WAAWpC,MAAOpC,EAAQwE,WAAWC,YAAYC,KAAK,MAAMlC,KAAK,GAAK2B,EAGlFc,GAAS9B,EAAIU,EAAUJ,GAAKyB,EAAahH,SAAW8B,EAAQK,MAAMC,OAClE4E,EAAa3G,MACXgE,GAAI0C,EAAS9B,IAGfa,EAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASG,EACT1C,KAAM,GAAK2B,EACXlB,EAAGgC,EAAShC,EACZE,EAAG8B,EAAS9B,EACZiB,MAAOA,SAiBfxH,EAASuI,YAAc,SAAUtB,EAAW9D,EAAQ+D,EAAMC,EAAQzD,EAAQN,EAASgE,GAEjFjE,EAAO8B,OAAOoC,QAAQ,SAAUzE,EAAO0E,GACrC,GAAIC,GAAoBnE,EAAQ2B,MAAMM,sBAAsBzC,EAAO0E,GACjEE,EAAQP,EAAU3F,SAAW6B,EAAO8B,OAAOnE,OAC3C2G,EAAMR,EAAUJ,GAAKW,EAAQF,CAG/B,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAInE,EAAQ2B,MAAM2C,SAAU,CAC1B,GAAIC,GAAcT,EAAKzB,KAAK,QAC1BmB,GAAIK,EAAUL,GACdC,GAAIY,EACJX,GAAIG,EAAUH,GACdC,GAAIU,IACFrE,EAAQwE,WAAWV,KAAM9D,EAAQwE,WAAWY,UAAUV,KAAK,KAG/DV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTf,GAAIK,EAAUL,GACdC,GAAIY,EACJX,GAAIG,EAAUH,GACdC,GAAIU,IAIR,GAAIrE,EAAQ2B,MAAMqD,UAAW,CAG3B,GAAIC,IACFhC,EAAgC,UAA7BjD,EAAQ2B,MAAM0D,WAAyB/E,EAASN,EAAQ2B,MAAMrB,OAASN,EAAQI,aAAeJ,EAAQI,aACzG+C,EAAGkB,EAAM,GAGPa,EAAenB,EAAO1B,KAAK,QAC7BC,GAAiC,UAA7BtC,EAAQ2B,MAAM0D,WAAyB/E,EAASN,EAAQ2B,MAAMrB,OAASN,EAAQI,aAAeJ,EAAQI,aAC1GmC,GAAI8B,EAAM,EACViB,cAA4C,UAA7BtF,EAAQ2B,MAAM0D,WAAyB,MAAQ,UAC5DrF,EAAQwE,WAAWpC,MAAOpC,EAAQwE,WAAWY,UAAUV,KAAK,MAAMlC,KAAK,GAAK2B,EAEhFH,GAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASG,EACT1C,KAAM,GAAK2B,EACXlB,EAAGgC,EAAShC,EACZE,EAAG8B,EAAS9B,EACZiB,MAAOA,SAgBfxH,EAAS2I,aAAe,SAAU1B,EAAW9D,EAAQf,EAAMkF,GACzD,OACEjB,EAAGY,EAAUL,GAAKK,EAAU5F,QAAUe,EAAKtB,OAASwG,EACpDf,EAAGU,EAAUJ,GAAKI,EAAU3F,UAAYc,EAAKkF,GAASnE,EAAOoB,MAAQpB,EAAOI,MAAQJ,EAAOyB,QAe/F5E,EAAS4I,gBAAkB,SAAUC,EAAgBzF,EAAS0F,EAAmB1B,GAM/E,QAAS2B,KACP,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiBjJ,EAASS,UAAWyI,GAEjCJ,EACF,IAAKxG,EAAI,EAAGA,EAAIwG,EAAkBhI,OAAQwB,IAAK,CAC7C,GAAI6G,GAAMjJ,EAAOkJ,WAAWN,EAAkBxG,GAAG,GAC7C6G,GAAIE,UACNJ,EAAiBjJ,EAASS,OAAOwI,EAAgBH,EAAkBxG,GAAG,KAKzE8E,GACDA,EAAaW,KAAK,kBAChBiB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoBlC,QAAQ,SAAS8B,GACnCA,EAAIK,eAAeT,KA5BvB,GACEE,GAEA3G,EAHE4G,EAAclJ,EAASS,OAAOT,EAASS,UAAWoI,GAAiBzF,GAErEmG,IA8BF,KAAKrJ,EAAOkJ,WACV,KAAM,iEACD,IAAIN,EAET,IAAKxG,EAAI,EAAGA,EAAIwG,EAAkBhI,OAAQwB,IAAK,CAC7C,GAAI6G,GAAMjJ,EAAOkJ,WAAWN,EAAkBxG,GAAG,GACjD6G,GAAIM,YAAYV,GAChBQ,EAAoBrE,KAAKiE,GAM7B,MAFAJ,MAGEW,GAAIT,kBACF,MAAOjJ,GAASS,UAAWwI,IAE7BK,0BAA2BA,IAK/BtJ,EAAS2J,kBAAoB,SAAUC,EAAKC,GAE1C,IAAK,GADDC,MACKxH,EAAI,EAAGyH,EAAOH,EAAI9I,OAAQiJ,EAAO,GAAKF,EAAIvH,EAAGA,GAAK,EAAG,CAC5D,GAAI0H,KACD3D,GAAIuD,EAAItH,EAAI,GAAIiE,GAAIqD,EAAItH,EAAI,KAC5B+D,GAAIuD,EAAItH,GAAIiE,GAAIqD,EAAItH,EAAI,KACxB+D,GAAIuD,EAAItH,EAAI,GAAIiE,GAAIqD,EAAItH,EAAI,KAC5B+D,GAAIuD,EAAItH,EAAI,GAAIiE,GAAIqD,EAAItH,EAAI,IAE3BuH,GACGvH,EAEMyH,EAAO,IAAMzH,EACtB0H,EAAE,IAAM3D,GAAIuD,EAAI,GAAIrD,GAAIqD,EAAI,IACnBG,EAAO,IAAMzH,IACtB0H,EAAE,IAAM3D,GAAIuD,EAAI,GAAIrD,GAAIqD,EAAI,IAC5BI,EAAE,IAAM3D,GAAIuD,EAAI,GAAIrD,GAAIqD,EAAI,KAL5BI,EAAE,IAAM3D,GAAIuD,EAAIG,EAAO,GAAIxD,GAAIqD,EAAIG,EAAO,IAQxCA,EAAO,IAAMzH,EACf0H,EAAE,GAAKA,EAAE,GACC1H,IACV0H,EAAE,IAAM3D,GAAIuD,EAAItH,GAAIiE,GAAIqD,EAAItH,EAAI,KAGpCwH,EAAE5E,QAEI8E,EAAE,GAAG3D,EAAI,EAAI2D,EAAE,GAAG3D,EAAI2D,EAAE,GAAG3D,GAAK,IAChC2D,EAAE,GAAGzD,EAAI,EAAIyD,EAAE,GAAGzD,EAAIyD,EAAE,GAAGzD,GAAK,GACjCyD,EAAE,GAAG3D,EAAI,EAAI2D,EAAE,GAAG3D,EAAI2D,EAAE,GAAG3D,GAAK,GAChC2D,EAAE,GAAGzD,EAAI,EAAIyD,EAAE,GAAGzD,EAAIyD,EAAE,GAAGzD,GAAK,EACjCyD,EAAE,GAAG3D,EACL2D,EAAE,GAAGzD,IAKX,MAAOuD,KAGT5J,OAAQC,SAAUH,GAMnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAASiK,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAOjF,KAAKkF,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAOrJ,cACVuJ,GAASF,UAIXE,GAASF,IAYtB,QAASpC,GAAKoC,EAAO/H,GAEhBiI,EAASF,IACVE,EAASF,GAAO9C,QAAQ,SAAS+C,GAC/BA,EAAQhI,KAhDd,GAAIiI,KAqDJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpBvC,KAAMA,KAIV7H,OAAQC,SAAUH,GAMnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAASyK,GAAYC,GACnB,GAAIC,KACJ,IAAID,EAAK5J,OACP,IAAK,GAAIwB,GAAI,EAAGA,EAAIoI,EAAK5J,OAAQwB,IAC/BqI,EAAIzF,KAAKwF,EAAKpI,GAGlB,OAAOqI,GA4CT,QAASlK,GAAOmK,EAAYC,GAC1B,GAAIC,GAAaD,GAAsB9K,KAAKgL,WAAa/K,EAASgL,MAC9DC,EAAQC,OAAOC,OAAOL,EAE1B9K,GAASgL,MAAMI,iBAAiBH,EAAOL,EAEvC,IAAIS,GAAS,WACX,GACEC,GADEC,EAAKN,EAAMO,aAAe,YAU9B,OALAF,GAAWvL,OAASC,EAAWkL,OAAOC,OAAOF,GAASlL,KACtDwL,EAAGE,MAAMH,EAAUI,MAAMX,UAAUY,MAAMC,KAAKC,UAAW,IAIlDP,EAOT,OAJAD,GAAON,UAAYE,EACnBI,EAAOS,MAAQhB,EACfO,EAAO5K,OAASV,KAAKU,OAEd4K,EA0FT,QAASU,GAAIC,EAAapB,GACxB,GAAG7K,OAASC,EAASgL,MACnB,KAAM,IAAIiB,OAAM,iFAIlB,IAAIC,QACDC,OAAOH,GACPI,IAAI,SAAUrB,GACb,MAAOA,aAAqBsB,UAAWtB,EAAUA,UAAYA,IAG7DuB,EAAkBtM,EAASgL,MAAMI,iBAAiBK,MAAMhK,OAAWyK,EAGvE,cADOI,GAAgBd,YAChBzL,KAAKU,OAAOmK,EAAY0B,GAIjC,QAASlB,KACP,GAAImB,GAAO9B,EAAYoB,WACnBnL,EAAS6L,EAAK,EAYlB,OAVAA,GAAKhC,OAAO,EAAGgC,EAAKzL,OAAS,GAAGuG,QAAQ,SAAU1G,GAChDuK,OAAOsB,oBAAoB7L,GAAQ0G,QAAQ,SAAUoF,SAE5C/L,GAAO+L,GAEdvB,OAAOwB,eAAehM,EAAQ+L,EAC5BvB,OAAOyB,yBAAyBhM,EAAQ8L,QAIvC/L,EAGTV,EAASgL,OACPvK,OAAQA,EACRsL,IAAKA,EACLX,iBAAkBA,IAGpBlL,OAAQC,SAAUH,GAMnB,SAASE,EAAQC,EAAUH,GAC1B,YAaA,SAAS4M,KACP7M,KAAK8M,YAAY9M,KAAK6I,gBAAgBK,gBAQxC,QAAS6D,KACP5M,EAAO6M,oBAAoB,SAAUhN,KAAK6M,QAC1C7M,KAAK6I,gBAAgBU,4BAUvB,QAAS0D,GAAG7C,EAAOC,GACjBrK,KAAKqH,aAAa8C,gBAAgBC,EAAOC,GAU3C,QAAS6C,GAAI9C,EAAOC,GAClBrK,KAAKqH,aAAakD,mBAAmBH,EAAOC,GAY9C,QAAS8C,GAAKjM,EAAOmB,EAAMgB,EAAS0F,GAClC/I,KAAKqB,UAAYpB,EAASgB,cAAcC,GACxClB,KAAKqC,KAAOA,EACZrC,KAAKqD,QAAUA,EACfrD,KAAK+I,kBAAoBA,EACzB/I,KAAKqH,aAAepH,EAASiK,eAE7B/J,EAAOiN,iBAAiB,SAAUpN,KAAK6M,OAAOQ,KAAKrN,OAInDsN,WAAW,WAITtN,KAAK6I,gBAAkB5I,EAAS4I,mBAAoB7I,KAAKqD,QAASrD,KAAK+I,kBAAmB/I,KAAKqH,cAC/FrH,KAAK8M,YAAY9M,KAAK6I,gBAAgBK,iBACtCmE,KAAKrN,MAAO,GAIhBC,EAASkN,KAAOlN,EAASgL,MAAMvK,QAC7B+K,YAAa0B,EACbtE,gBAAiBnH,OACjBL,UAAWK,OACXD,IAAKC,OACL2F,aAAc3F,OACdoL,YAAa,WACX,KAAM,IAAIZ,OAAM,2CAElBW,OAAQA,EACRE,OAAQA,EACRE,GAAIA,EACJC,IAAKA,EACLhN,QAASD,EAASC,WAGpBC,OAAQC,SAAUH,GAMnB,SAASE,EAAQC,EAAUH,GAC1B,YAEAA,GAASsN,OACPC,cAAe,WACfC,OAAQ,KACRC,IAAK,6CAcPzN,EAASgC,IAAM,SAAS0L,EAAMC,EAAYpM,EAAWqM,EAAQC,GAc3D,QAASlM,GAAKmM,EAAMH,EAAYI,GAc9B,MAbA7C,QAAO8C,KAAKL,GAAYtG,QAAQ,SAAS4G,GAEhBxM,SAApBkM,EAAWM,KAIXF,EACDD,EAAKI,eAAeH,GAAK/N,EAASsN,MAAME,OAAQ,IAAKS,GAAKnG,KAAK,IAAK6F,EAAWM,IAE/EH,EAAKK,aAAaF,EAAKN,EAAWM,OAI/BH,EAaT,QAASrI,GAAKiI,EAAMC,EAAYpM,EAAW6M,EAAYP,GACrD,GAAIC,GAAO3N,EAASkO,gBAAgBC,EAAOZ,EAuB3C,OApBY,QAATA,GACDI,EAAKI,eAAeZ,EAAOtN,EAASsN,MAAMC,cAAevN,EAASsN,MAAMG,KAGvEW,IACEP,GAAeO,EAAWG,WAC3BH,EAAWI,aAAaV,EAAMM,EAAWG,YAEzCH,EAAWnM,YAAY6L,IAIxBH,GACDhM,EAAKmM,EAAMH,GAGVpM,GACDM,EAASiM,EAAMvM,GAGVuM,EAgBT,QAASW,GAAcC,EAASrI,EAAGE,EAAGlF,EAAOC,EAAQC,EAAWqM,EAAQC,GAGtE,GAAsB,gBAAZa,GAAsB,CAC9B,GAAItN,GAAYjB,EAASwO,cAAc,MACvCvN,GAAUwN,UAAYF,EACtBA,EAAUtN,EAAUmN,WAItBG,EAAQP,aAAa,QAASU,EAI9B,IAAIC,GAAQ9O,EAASgC,IAAI,iBACvBqE,EAAGA,EACHE,EAAGA,EACHlF,MAAOA,EACPC,OAAQA,GACPC,EAAWqM,EAAQC,EAKtB,OAFAiB,GAAM5M,MAAMD,YAAYyM,GAEjBI,EAUT,QAASlJ,GAAKkI,EAAMiB,GAClBjB,EAAK7L,YAAY9B,EAAS6O,eAAeD,IAS3C,QAAShN,GAAM+L,GACb,KAAOA,EAAKS,YACVT,EAAKmB,YAAYnB,EAAKS,YAU1B,QAAS1I,GAAOiI,GACdA,EAAKM,WAAWa,YAAYnB,GAU9B,QAAS/M,GAAQ+M,EAAMoB,GACrBpB,EAAKM,WAAWe,aAAaD,EAAUpB,GAWzC,QAASsB,GAAOtB,EAAMuB,EAAOxB,GACxBA,GAAeC,EAAKS,WACrBT,EAAKU,aAAaa,EAAOvB,EAAKS,YAE9BT,EAAK7L,YAAYoN,GAUrB,QAASC,GAAQxB,GACf,MAAOA,GAAKyB,aAAa,SAAWzB,EAAKyB,aAAa,SAASC,OAAOC,MAAM,UAU9E,QAAS5N,GAASiM,EAAM4B,GACtB5B,EAAKK,aAAa,QAChBmB,EAAQxB,GACL3B,OAAOuD,EAAMF,OAAOC,MAAM,QAC1BE,OAAO,SAASlK,EAAMgC,EAAKmI,GAC1B,MAAOA,GAAKpF,QAAQ/E,KAAUgC,IAC7BK,KAAK,MAWd,QAAS+H,GAAY/B,EAAM4B,GACzB,GAAII,GAAiBJ,EAAMF,OAAOC,MAAM,MAExC3B,GAAKK,aAAa,QAASmB,EAAQxB,GAAM6B,OAAO,SAASjC,GACvD,MAAwC,KAAjCoC,EAAetF,QAAQkD,KAC7B5F,KAAK,MASV,QAASlG,GAAiBkM,GACxBA,EAAKK,aAAa,QAAS,IAU7B,QAAS7M,GAAOwM,GACd,MAAOA,GAAKiC,cAAgBlN,KAAKiC,MAAMgJ,EAAKkC,UAAU1O,SAAWwM,EAAKM,WAAW2B,aAUnF,QAAS1O,GAAMyM,GACb,MAAOA,GAAKmC,aAAepN,KAAKiC,MAAMgJ,EAAKkC,UAAU3O,QAAUyM,EAAKM,WAAW6B,YA7OjF,GAAI3B,GAAQ,6BACVhB,EAAQ,gCACRuB,EAAU,8BA8OZ,QACE3M,MAAOuD,EAAKiI,EAAMC,EAAYpM,EAAWqM,EAASA,EAAO1L,MAAQT,OAAWoM,GAC5EqC,QAAStC,EACTA,OAAQ,WACN,MAAO7N,MAAKmQ,SAEdvO,KAAM,SAASgM,EAAYI,GAEzB,MADApM,GAAK5B,KAAKmC,MAAOyL,EAAYI,GACtBhO,MAETgC,MAAO,WAEL,MADAA,GAAMhC,KAAKmC,OACJnC,MAET8F,OAAQ,WAEN,MADAA,GAAO9F,KAAKmC,OACLnC,KAAK6N,UAEd7M,QAAS,SAASoP,GAGhB,MAFAA,GAAWD,QAAUnQ,KAAKmQ,QAC1BnP,EAAQhB,KAAKmC,MAAOiO,EAAWjO,OACxBiO,GAETf,OAAQ,SAASjH,EAAS0F,GAGxB,MAFA1F,GAAQ+H,QAAUnQ,KAClBqP,EAAOrP,KAAKmC,MAAOiG,EAAQjG,MAAO2L,GAC3B1F,GAET1C,KAAM,SAASiI,EAAMC,EAAYpM,EAAWsM,GAC1C,MAAO7N,GAASgC,IAAI0L,EAAMC,EAAYpM,EAAWxB,KAAM8N,IAEzDY,cAAe,SAASC,EAASrI,EAAGE,EAAGlF,EAAOC,EAAQC,EAAWsM,GAC/D,MAAOY,GAAcC,EAASrI,EAAGE,EAAGlF,EAAOC,EAAQC,EAAWxB,KAAM8N,IAEtEjI,KAAM,SAASmJ,GAEb,MADAnJ,GAAK7F,KAAKmC,MAAO6M,GACVhP,MAET8B,SAAU,SAAS6N,GAEjB,MADA7N,GAAS9B,KAAKmC,MAAOwN,GACd3P,MAET8P,YAAa,SAASH,GAEpB,MADAG,GAAY9P,KAAKmC,MAAOwN,GACjB3P,MAET6B,iBAAkB,WAEhB,MADAA,GAAiB7B,KAAKmC,OACfnC,MAETuP,QAAS,WACP,MAAOA,GAAQvP,KAAKmC,QAEtBZ,OAAQ,WACN,MAAOA,GAAOvB,KAAKmC,QAErBb,MAAO,WACL,MAAOA,GAAMtB,KAAKmC,WAKxBhC,OAAQC,SAAUH,GAQnB,SAASE,EAAQC,EAAUH,GAC1B,YAwCA,SAAS6M,GAAYzJ,GACnB,GAAIsD,GACFC,EAEAxD,EADAiN,KAEAlM,EAAiBlE,EAASwC,mBAAmBxC,EAASmC,aAAapC,KAAKqC,MAAOrC,KAAKqC,KAAK+E,OAAOrG,OAGlGf,MAAKyB,IAAMxB,EAASmB,UAAUpB,KAAKqB,UAAWgC,EAAQ/B,MAAO+B,EAAQ9B,OAAQ8B,EAAQwE,WAAWyI,OAGhGlN,EAASnD,EAASiE,UAAUlE,KAAKyB,IAAK0C,EAAgBd,GAEtDsD,EAActD,EAAQK,MAAMC,OACxBN,EAAQK,MAAM2E,YAChB1B,GAAe1G,EAASmF,qBACtBpF,KAAKyB,IACLzB,KAAKqC,KAAK+E,QACT/D,EAAQwE,WAAWpC,MAAOpC,EAAQwE,WAAWC,YAAYC,KAAK,KAC/D1E,EAAQK,MAAM4B,sBACd,WAIJsB,EAAcvD,EAAQ2B,MAAMrB,OACxBN,EAAQ2B,MAAMqD,YAChBzB,GAAe3G,EAASmF,qBACtBpF,KAAKyB,IACL2B,EAAO8B,QACN7B,EAAQwE,WAAWpC,MAAOpC,EAAQwE,WAAWC,YAAYC,KAAK,KAC/D1E,EAAQ2B,MAAMM,sBACd,SAIJ,IAAI4B,GAAYjH,EAASyG,gBAAgB1G,KAAKyB,IAAK4B,EAASsD,EAAaC,GAErEQ,EAASpH,KAAKyB,IAAIiE,KAAK,KACzByB,EAAOnH,KAAKyB,IAAIiE,KAAK,IAEvBzF,GAASgH,YAAYC,EAAWlH,KAAKqC,KAAM8E,EAAMC,EAAQ/D,EAASrD,KAAKqH,cACvEpH,EAASuI,YAAYtB,EAAW9D,EAAQ+D,EAAMC,EAAQR,EAAavD,EAASrD,KAAKqH,aAIjF,KAAK,GAAI9E,GAAI,EAAGA,EAAIvC,KAAKqC,KAAKG,OAAOzB,OAAQwB,IAAK,CAChD8N,EAAa9N,GAAKvC,KAAKyB,IAAIiE,KAAK,KAG7B1F,KAAKqC,KAAKG,OAAOD,GAAGoL,MACrB0C,EAAa9N,GAAGX,MACd2O,cAAevQ,KAAKqC,KAAKG,OAAOD,GAAGoL,MAClC1N,EAASsN,MAAMG,KAIpB2C,EAAa9N,GAAGT,UACduB,EAAQwE,WAAWrF,OAClBxC,KAAKqC,KAAKG,OAAOD,GAAGf,WAAa6B,EAAQwE,WAAWrF,OAAS,IAAMvC,EAASM,cAAcgC,IAC3FwF,KAAK,KAMP,KAAK,GAJDkC,GAEFuG,EADAC,KAGO9N,EAAI,EAAGA,EAAIwB,EAAe5B,GAAGxB,OAAQ4B,IAC5CsH,EAAIhK,EAAS2I,aAAa1B,EAAW9D,EAAQe,EAAe5B,GAAII,GAChE8N,EAAgBtL,KAAK8E,EAAE3D,EAAG2D,EAAEzD,GAIxBnD,EAAQqN,YACVF,EAAQH,EAAa9N,GAAGmD,KAAK,QAC3BmB,GAAIoD,EAAE3D,EACNQ,GAAImD,EAAEzD,EACNO,GAAIkD,EAAE3D,EAAI,IACVU,GAAIiD,EAAEzD,GACLnD,EAAQwE,WAAW2I,OAAO5O,MAC3BiB,MAASsB,EAAe5B,GAAGI,IAC1B1C,EAASsN,MAAMG,KAElB1N,KAAKqH,aAAaW,KAAK,QACrBC,KAAM,QACNpF,MAAOsB,EAAe5B,GAAGI,GACzB4E,MAAO5E,EACPwF,MAAOkI,EAAa9N,GACpB6F,QAASoI,EACTlK,EAAG2D,EAAE3D,EACLE,EAAGyD,EAAEzD,IAMX,IAAInD,EAAQsN,UAAYtN,EAAQuN,SAAU,CAExC,GAAIC,IAAgB,IAAMJ,EAAgB,GAAK,IAAMA,EAAgB,GAGrE,IAAIpN,EAAQyN,YAAcL,EAAgB1P,OAAS,EAGjD,IAAI,GADAgQ,GAAK9Q,EAAS2J,kBAAkB6G,GAC5BO,EAAI,EAAGA,EAAID,EAAGhQ,OAAQiQ,IAC5BH,EAAa1L,KAAK,IAAM4L,EAAGC,GAAGjJ,YAGhC,KAAI,GAAIkJ,GAAI,EAAGA,EAAIR,EAAgB1P,OAAQkQ,GAAK,EAC9CJ,EAAa1L,KAAK,IAAMsL,EAAgBQ,EAAI,GAAK,IAAMR,EAAgBQ,GAI3E,IAAG5N,EAAQuN,SAAU,CAGnB,GAAIM,GAAWpO,KAAKyB,IAAIzB,KAAK0B,IAAInB,EAAQ6N,SAAU9N,EAAOU,MAAOV,EAAOa,KAGpEkN,EAAmBN,EAAajF,QAGhCwF,EAAoBnR,EAAS2I,aAAa1B,EAAW9D,GAAS8N,GAAW,EAE7EC,GAAiB3G,OAAO,EAAG,EAAG,IAAM4G,EAAkB9K,EAAI,IAAM8K,EAAkB5K,GAClF2K,EAAiB,GAAK,IAAMV,EAAgB,GAAK,IAAMA,EAAgB,GACvEU,EAAiBhM,KAAK,IAAMsL,EAAgBA,EAAgB1P,OAAS,GAAK,IAAMqQ,EAAkB5K,GAGlG6J,EAAa9N,GAAGmD,KAAK,QACnBqE,EAAGoH,EAAiBpJ,KAAK,KACxB1E,EAAQwE,WAAWwJ,MAAM,GAAMzP,MAChCsD,OAAUf,EAAe5B,IACxBtC,EAASsN,MAAMG,KAGjBrK,EAAQsN,UACTN,EAAa9N,GAAGmD,KAAK,QACnBqE,EAAG8G,EAAa9I,KAAK,KACpB1E,EAAQwE,WAAWyJ,MAAM,GAAM1P,MAChCsD,OAAUf,EAAe5B,IACxBtC,EAASsN,MAAMG,OAwI1B,QAAS6D,GAAKrQ,EAAOmB,EAAMgB,EAAS0F,GAClC9I,EAASsR,KAAKxF,MAAMN,YAAYI,KAAK7L,KACnCkB,EACAmB,EACApC,EAASS,OAAOT,EAASS,UAAWoI,GAAiBzF,GACrD0F,GA9TJ,GAAID,IACFpF,OACEC,OAAQ,GACR0E,WAAW,EACXV,UAAU,EACVrC,sBAAuBrF,EAASI,MAElC2E,OACErB,OAAQ,GACR0E,WAAW,EACXV,UAAU,EACVe,WAAY,QACZpD,sBAAuBrF,EAASI,KAChC4E,cAAe,IAEjB3D,MAAOI,OACPH,OAAQG,OACRiP,UAAU,EACVD,WAAW,EACXE,UAAU,EACVM,SAAU,EACVJ,YAAY,EACZ7M,IAAKvC,OACLoC,KAAMpC,OACN+B,aAAc,EACdoE,YACEyI,MAAO,gBACP7K,MAAO,WACPjD,OAAQ,YACR8O,KAAM,UACNd,MAAO,WACPa,KAAM,UACNlK,KAAM,UACNsB,SAAU,cACVX,WAAY,iBAgShB7H,GAASsR,KAAOtR,EAASkN,KAAKzM,QAC5B+K,YAAa8F,EACbzE,YAAaA,KAGf3M,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAoCA,SAAS6M,GAAYzJ,GACnB,GAAIsD,GACFC,EAEAxD,EADAiN,KAEAlM,EAAiBlE,EAASwC,mBAAmBxC,EAASmC,aAAapC,KAAKqC,MAAOrC,KAAKqC,KAAK+E,OAAOrG,OAGlGf,MAAKyB,IAAMxB,EAASmB,UAAUpB,KAAKqB,UAAWgC,EAAQ/B,MAAO+B,EAAQ9B,OAAQ8B,EAAQwE,WAAWyI,OAGhGlN,EAASnD,EAASiE,UAAUlE,KAAKyB,IAAK0C,EAAgBd,EAAS,GAE/DsD,EAActD,EAAQK,MAAMC,OACxBN,EAAQK,MAAM2E,YAChB1B,GAAe1G,EAASmF,qBACtBpF,KAAKyB,IACLzB,KAAKqC,KAAK+E,QACT/D,EAAQwE,WAAWpC,MAAOpC,EAAQwE,WAAWC,YAAYC,KAAK,KAC/D1E,EAAQK,MAAM4B,sBACd,WAIJsB,EAAcvD,EAAQ2B,MAAMrB,OACxBN,EAAQ2B,MAAMqD,YAChBzB,GAAe3G,EAASmF,qBACtBpF,KAAKyB,IACL2B,EAAO8B,QACN7B,EAAQwE,WAAWpC,MAAOpC,EAAQwE,WAAWC,YAAYC,KAAK,KAC/D1E,EAAQ2B,MAAMM,sBACd,SAIJ,IAAI4B,GAAYjH,EAASyG,gBAAgB1G,KAAKyB,IAAK4B,EAASsD,EAAaC,GAErEQ,EAASpH,KAAKyB,IAAIiE,KAAK,KACzByB,EAAOnH,KAAKyB,IAAIiE,KAAK,KAErB8L,EAAYvR,EAAS2I,aAAa1B,EAAW9D,GAAS,GAAI,EAE5DnD,GAASgH,YAAYC,EAAWlH,KAAKqC,KAAM8E,EAAMC,EAAQ/D,EAASrD,KAAKqH,cACvEpH,EAASuI,YAAYtB,EAAW9D,EAAQ+D,EAAMC,EAAQR,EAAavD,EAASrD,KAAKqH,aAIjF,KAAK,GAAI9E,GAAI,EAAGA,EAAIvC,KAAKqC,KAAKG,OAAOzB,OAAQwB,IAAK,CAEhD,GAAIkP,GAAQlP,GAAKvC,KAAKqC,KAAKG,OAAOzB,OAAS,GAAK,EAE9C2Q,EAAkBxK,EAAU5F,QAAU6C,EAAe5B,GAAGxB,OAAS,CAEnEsP,GAAa9N,GAAKvC,KAAKyB,IAAIiE,KAAK,KAG7B1F,KAAKqC,KAAKG,OAAOD,GAAGoL,MACrB0C,EAAa9N,GAAGX,MACd2O,cAAevQ,KAAKqC,KAAKG,OAAOD,GAAGoL,MAClC1N,EAASsN,MAAMG,KAIpB2C,EAAa9N,GAAGT,UACduB,EAAQwE,WAAWrF,OAClBxC,KAAKqC,KAAKG,OAAOD,GAAGf,WAAa6B,EAAQwE,WAAWrF,OAAS,IAAMvC,EAASM,cAAcgC,IAC3FwF,KAAK,KAEP,KAAI,GAAIpF,GAAI,EAAGA,EAAIwB,EAAe5B,GAAGxB,OAAQ4B,IAAK,CAChD,GACEgP,GADE1H,EAAIhK,EAAS2I,aAAa1B,EAAW9D,EAAQe,EAAe5B,GAAII,EAKpEsH,GAAE3D,GAAKoL,EAAmBD,EAAQpO,EAAQuO,kBAE1CD,EAAMtB,EAAa9N,GAAGmD,KAAK,QACzBmB,GAAIoD,EAAE3D,EACNQ,GAAI0K,EAAUhL,EACdO,GAAIkD,EAAE3D,EACNU,GAAIiD,EAAEzD,GACLnD,EAAQwE,WAAW8J,KAAK/P,MACzBiB,MAASsB,EAAe5B,GAAGI,IAC1B1C,EAASsN,MAAMG,KAElB1N,KAAKqH,aAAaW,KAAK,QACrBC,KAAM,MACNpF,MAAOsB,EAAe5B,GAAGI,GACzB4E,MAAO5E,EACPwF,MAAOkI,EAAa9N,GACpB6F,QAASuJ,EACT9K,GAAIoD,EAAE3D,EACNQ,GAAI0K,EAAUhL,EACdO,GAAIkD,EAAE3D,EACNU,GAAIiD,EAAEzD,MAuGd,QAASqL,GAAI3Q,EAAOmB,EAAMgB,EAAS0F,GACjC9I,EAAS4R,IAAI9F,MAAMN,YAAYI,KAAK7L,KAClCkB,EACAmB,EACApC,EAASS,OAAOT,EAASS,UAAWoI,GAAiBzF,GACrD0F,GA5OJ,GAAID,IACFpF,OACEC,OAAQ,GACR0E,WAAW,EACXV,UAAU,EACVrC,sBAAuBrF,EAASI,MAElC2E,OACErB,OAAQ,GACR0E,WAAW,EACXV,UAAU,EACVe,WAAY,QACZpD,sBAAuBrF,EAASI,KAChC4E,cAAe,IAEjB3D,MAAOI,OACPH,OAAQG,OACRoC,KAAMpC,OACNuC,IAAKvC,OACL+B,aAAc,EACdmO,kBAAmB,GACnB/J,YACEyI,MAAO,eACP7K,MAAO,WACPjD,OAAQ,YACRmP,IAAK,SACLG,KAAM,UACNC,MAAO,WACP5K,KAAM,UACNsB,SAAU,cACVX,WAAY,iBAkNhB7H,GAAS4R,IAAM5R,EAASkN,KAAKzM,QAC3B+K,YAAaoG,EACb/E,YAAaA,KAGf3M,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAwBA,SAAS+R,GAAwBC,EAAQxM,EAAOyM,GAC9C,GAAIC,GAAa1M,EAAMa,EAAI2L,EAAO3L,CAElC,OAAG6L,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SAIX,QAASpF,GAAYzJ,GACnB,GACE6D,GACAhB,EACAkM,EACAC,EAJEhC,KAKFiC,EAAajP,EAAQiP,WACrB5P,EAAYzC,EAASmC,aAAapC,KAAKqC,KAGzCrC,MAAKyB,IAAMxB,EAASmB,UAAUpB,KAAKqB,UAAWgC,EAAQ/B,MAAO+B,EAAQ9B,OAAQ8B,EAAQwE,WAAWyI,OAEhGpJ,EAAYjH,EAASyG,gBAAgB1G,KAAKyB,IAAK4B,EAAS,EAAG,GAE3D6C,EAASpD,KAAK0B,IAAI0C,EAAU5F,QAAU,EAAG4F,EAAU3F,SAAW,GAE9D8Q,EAAehP,EAAQkP,OAAS7P,EAAU8P,OAAO,SAASC,EAAeC,GACvE,MAAOD,GAAgBC,GACtB,GAKHxM,GAAU7C,EAAQsP,MAAQtP,EAAQuP,WAAa,EAAK,EAIpDR,EAAc/O,EAAQsP,MAAQzM,EAASA,EAAS,EAEhDkM,GAAe/O,EAAQwP,WAevB,KAAK,GAZDZ,IACF3L,EAAGY,EAAUL,GAAKK,EAAU5F,QAAU,EACtCkF,EAAGU,EAAUF,GAAKE,EAAU3F,SAAW,GAIrCuR,EAEU,IAFa9S,KAAKqC,KAAKG,OAAOoN,OAAO,SAASmD,GAC1D,MAAe,KAARA,IACNhS,OAIMwB,EAAI,EAAGA,EAAIvC,KAAKqC,KAAKG,OAAOzB,OAAQwB,IAAK,CAChD8N,EAAa9N,GAAKvC,KAAKyB,IAAIiE,KAAK,IAAK,KAAM,MAAM,GAG9C1F,KAAKqC,KAAKG,OAAOD,GAAGoL,MACrB0C,EAAa9N,GAAGX,MACd2O,cAAevQ,KAAKqC,KAAKG,OAAOD,GAAGoL,MAClC1N,EAASsN,MAAMG,KAIpB2C,EAAa9N,GAAGT,UACduB,EAAQwE,WAAWrF,OAClBxC,KAAKqC,KAAKG,OAAOD,GAAGf,WAAa6B,EAAQwE,WAAWrF,OAAS,IAAMvC,EAASM,cAAcgC,IAC3FwF,KAAK,KAEP,IAAIiL,GAAWV,EAAa5P,EAAUH,GAAK8P,EAAe,GAGvDW,GAAWV,IAAe,MAC3BU,GAAY,IAGd,IAAIC,GAAQhT,EAAS8F,iBAAiBkM,EAAO3L,EAAG2L,EAAOzL,EAAGN,EAAQoM,GAAoB,IAAN/P,GAAWuQ,EAAuB,EAAI,KACpHI,EAAMjT,EAAS8F,iBAAiBkM,EAAO3L,EAAG2L,EAAOzL,EAAGN,EAAQ8M,GAC5DG,EAAoC,KAAzBH,EAAWV,EAAoB,IAAM,IAChDvI,GAEE,IAAKmJ,EAAI5M,EAAG4M,EAAI1M,EAEhB,IAAKN,EAAQA,EAAQ,EAAGiN,EAAU,EAAGF,EAAM3M,EAAG2M,EAAMzM,EAIrDnD,GAAQsP,SAAU,GACnB5I,EAAE5E,KAAK,IAAK8M,EAAO3L,EAAG2L,EAAOzL,EAK/B,IAAI4M,GAAO/C,EAAa9N,GAAGmD,KAAK,QAC9BqE,EAAGA,EAAEhC,KAAK,MACT1E,EAAQwE,WAAW+D,OAASvI,EAAQsP,MAAQ,IAAMtP,EAAQwE,WAAW8K,MAAQ,IA6BhF,IA1BAS,EAAKxR,MACHiB,MAASH,EAAUH,IAClBtC,EAASsN,MAAMG,KAGfrK,EAAQsP,SAAU,GACnBS,EAAKxR,MACHG,MAAS,mBAAqBsB,EAAQuP,WAAc,OAKxD5S,KAAKqH,aAAaW,KAAK,QACrBC,KAAM,QACNpF,MAAOH,EAAUH,GACjB8P,aAAcA,EACd9K,MAAOhF,EACP4F,MAAOkI,EAAa9N,GACpB6F,QAASgL,EACTnB,OAAQA,EACR/L,OAAQA,EACRoM,WAAYA,EACZU,SAAUA,IAIT3P,EAAQgF,UAAW,CAEpB,GAAIgL,GAAgBpT,EAAS8F,iBAAiBkM,EAAO3L,EAAG2L,EAAOzL,EAAG4L,EAAaE,GAAcU,EAAWV,GAAc,GACpH9K,EAAoBnE,EAAQiC,sBAAsBtF,KAAKqC,KAAK+E,OAASpH,KAAKqC,KAAK+E,OAAO7E,GAAKG,EAAUH,GAAIA,GAEvGgG,EAAe8H,EAAa9N,GAAGmD,KAAK,QACtCC,GAAI0N,EAAc/M,EAClBV,GAAIyN,EAAc7M,EAClBmC,cAAeqJ,EAAwBC,EAAQoB,EAAehQ,EAAQiQ,iBACrEjQ,EAAQwE,WAAWpC,OAAOI,KAAK,GAAK2B,EAGvCxH,MAAKqH,aAAaW,KAAK,QACrBC,KAAM,QACNV,MAAOhF,EACP4F,MAAOkI,EAAa9N,GACpB6F,QAASG,EACT1C,KAAM,GAAK2B,EACXlB,EAAG+M,EAAc/M,EACjBE,EAAG6M,EAAc7M,IAMrB8L,EAAaU,GAoFjB,QAASO,GAAIrS,EAAOmB,EAAMgB,EAAS0F,GACjC9I,EAASsT,IAAIxH,MAAMN,YAAYI,KAAK7L,KAClCkB,EACAmB,EACApC,EAASS,OAAOT,EAASS,UAAWoI,GAAiBzF,GACrD0F,GAzQJ,GAAID,IACFxH,MAAOI,OACPH,OAAQG,OACR+B,aAAc,EACdoE,YACEyI,MAAO,eACP9N,OAAQ,YACRoJ,MAAO,WACP+G,MAAO,WACPlN,MAAO,YAET6M,WAAY,EACZC,MAAO7Q,OACPiR,OAAO,EACPC,WAAY,GACZvK,WAAW,EACXwK,YAAa,EACbvN,sBAAuBrF,EAASI,KAChCmT,eAAe,EACfF,eAAgB,UA0PlBrT,GAASsT,IAAMtT,EAASkN,KAAKzM,QAC3B+K,YAAa8H,EACbzG,YAAaA,EACbkF,wBAAyBA,KAG3B7R,OAAQC,SAAUH,GAGbA","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.2.4\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.2.4';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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 svg.height() - (options.chartPadding * 2) - options.axisX.offset;\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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n while (true) {\n var length = Chartist.projectLength(svg, bounds.step / 2, bounds, options);\n if (length >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\n return bounds;\n };\n\n /**\n * Calculate the needed offset to fit in the labels\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} labelClass All css classes of the label\n * @param {Function} labelInterpolationFnc The function that interpolates the label value\n * @param {String} offsetFnc width or height. Will be used to call function on SVG element to get length\n * @return {Number} The number that represents the label offset in pixels\n */\n Chartist.calculateLabelOffset = function (svg, data, labelClass, labelInterpolationFnc, offsetFnc) {\n var offset = 0;\n for (var i = 0; i < data.length; i++) {\n // If interpolation function returns falsy value we skipp this label\n var interpolated = labelInterpolationFnc(data[i], i);\n if (!interpolated && interpolated !== 0) {\n continue;\n }\n\n var label = svg.elem('text', {\n dx: 0,\n dy: 0\n }, labelClass).text('' + interpolated);\n\n // Check if this is the largest label and update offset\n offset = Math.max(offset, label[offsetFnc]());\n // Remove label after offset Calculation\n label.remove();\n }\n\n return offset;\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 {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} xAxisOffset The offset of the x-axis to the border of the svg element\n * @param {Number} yAxisOffset The offset of the y-axis to the border of the svg element\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, xAxisOffset, yAxisOffset) {\n return {\n x1: options.chartPadding + yAxisOffset,\n y1: (Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xAxisOffset,\n x2: (Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding,\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n space = chartRect.width() / data.labels.length,\n pos = chartRect.x1 + space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n // Use config offset for setting labels of\n var labelPos = {\n x: pos + 2,\n y: 0\n };\n\n var labelElement = labels.elem('text', {\n dx: labelPos.x\n }, [options.classNames.label, options.classNames.horizontal].join(' ')).text('' + interpolatedValue);\n\n // TODO: should use 'alignment-baseline': 'hanging' but not supported in firefox. Instead using calculated height to offset y pos\n labelPos.y = chartRect.y1 + labelElement.height() + options.axisX.offset;\n labelElement.attr({\n dy: labelPos.y\n });\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Number} offset Offset for the y-axis\n * @param {Object} options The Object that contains all the optional values for the chart\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, offset, options, eventEmitter) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n space = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - space * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n // Use calculated offset and include padding for label x position\n // TODO: Review together with possibilities to style labels. Maybe we should start using fixed label width which is easier and also makes multi line labels with foreignObjects easier\n var labelPos = {\n x: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n y: pos - 2\n };\n\n var labelElement = labels.elem('text', {\n dx: options.axisY.labelAlign === 'right' ? offset - options.axisY.offset + options.chartPadding : options.chartPadding,\n dy: pos - 2,\n 'text-anchor': options.axisY.labelAlign === 'right' ? 'end' : 'start'\n }, [options.classNames.label, options.classNames.vertical].join(' ')).text('' + interpolatedValue);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPos.x,\n y: labelPos.y,\n space: space\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 * @returns {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\\'s 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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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\\'s 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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\\'s 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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\n cloneDefinitions: cloneDefinitions\n };\n\n }(window, document, Chartist));;/**\n * Base for all chart classes.\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 * @memberof Chartist.Line\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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.Line\n */\n function detach() {\n window.removeEventListener('resize', this.update);\n this.optionsProvider.removeMediaQueryListeners();\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.Line\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 }\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.Line\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 }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\n this.options = options;\n this.responsiveOptions = responsiveOptions;\n this.eventEmitter = Chartist.EventEmitter();\n\n window.addEventListener('resize', this.update.bind(this));\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 });\n\n }(window, document, Chartist));;/**\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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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} [x] The X position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [y] The Y position where the foreignObject will be placed relative to the next higher ViewBox\n * @param {String} [width] The width of the foreignElement\n * @param {String} [height] The height of the foreignElement\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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, x, y, width, height, className, parent, 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', xhtmlNs);\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 = Chartist.Svg('foreignObject', {\n x: x,\n y: y,\n width: width,\n height: height\n }, className, parent, 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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, x, y, width, height, className, insertFirst) {\n return foreignObject(content, x, y, width, height, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\n };\n\n }(window, document, Chartist));;/**\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 var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n this.data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g');\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 10,\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 15,\n showLabel: true,\n showGrid: true,\n labelAlign: 'right',\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 40\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n thin: 'ct-thin',\n thick: 'ct-thick',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var xAxisOffset,\n yAxisOffset,\n seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n xAxisOffset = options.axisX.offset;\n if (options.axisX.showLabel) {\n xAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n this.data.labels,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisX.labelInterpolationFnc,\n 'height'\n );\n }\n\n yAxisOffset = options.axisY.offset;\n if (options.axisY.showLabel) {\n yAxisOffset += Chartist.calculateLabelOffset(\n this.svg,\n bounds.values,\n [options.classNames.label, options.classNames.horizontal].join(' '),\n options.axisY.labelInterpolationFnc,\n 'width'\n );\n }\n\n var chartRect = Chartist.createChartRect(this.svg, options, xAxisOffset, yAxisOffset);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter);\n Chartist.createYAxis(chartRect, bounds, grid, labels, yAxisOffset, options, this.eventEmitter);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 10,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 15,\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 * // For the Y-Axis you can set a label alignment property of right or left\n * labelAlign: 'right',\n * // Interpolation function that allows you to intercept the value from the axis label\n * labelInterpolationFnc: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * point: 'ct-point',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * heigh: 10\n * });\n *\n */\n function Bar(query, data, options, responsiveOptions) {\n Chartist.Bar.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","j","normalizeDataArray","dataArray","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18727,"pos":18722,"col":16,"line":485,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18727,"pos":18722,"col":16,"line":485,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","on","off","Base","isSupported","addEventListener","bind","setTimeout","xmlNs","qualifiedName","prefix","uri","name","insertFirst","node","ns","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","remove","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","feature","implementation","hasFeature","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.3.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.3.1';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 * @returns {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\\'s 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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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\\'s 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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\\'s 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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\n cloneDefinitions: cloneDefinitions\n };\n\n }(window, document, Chartist));;/**\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.update);\n this.optionsProvider.removeMediaQueryListeners();\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 }\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 }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\n this.options = options;\n this.responsiveOptions = responsiveOptions;\n this.eventEmitter = Chartist.EventEmitter();\n this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility');\n\n window.addEventListener('resize', this.update.bind(this));\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 * 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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, attributes, className, parent, 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', xhtmlNs);\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 = parent.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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, attributes, className, insertFirst) {\n return foreignObject(content, attributes, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1');\n };\n\n }(window, document, Chartist));;/**\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g');\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/libdist/scss/chartist.scss b/libdist/scss/chartist.scss index a31d95a6..a8cfc7c2 100644 --- a/libdist/scss/chartist.scss +++ b/libdist/scss/chartist.scss @@ -29,9 +29,14 @@ } } -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size) { +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align) { + display: block; + width: 100%; + height: 100%; fill: $ct-text-color; + color: $ct-text-color; font-size: $ct-text-size; + text-align: $ct-text-align; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { @@ -82,11 +87,19 @@ } } -@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { +@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { .#{$ct-class-label} { @include ct-chart-label($ct-text-color, $ct-text-size); } + .#{$ct-class-label}.#{$ct-class-horizontal} { + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align); + } + + .#{$ct-class-label}.#{$ct-class-vertical} { + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align); + } + .#{$ct-class-grid} { @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); } diff --git a/libdist/scss/settings/_chartist-settings.scss b/libdist/scss/settings/_chartist-settings.scss index 51f69d1d..059e3d8a 100644 --- a/libdist/scss/settings/_chartist-settings.scss +++ b/libdist/scss/settings/_chartist-settings.scss @@ -25,6 +25,9 @@ $ct-container-ratio: (1/1.618) !default; // Text styles for labels $ct-text-color: rgba(0, 0, 0, 0.4) !default; $ct-text-size: 0.75rem !default; +$ct-text-align: left !default; +$ct-horizontal-text-align: left !default; +$ct-vertical-text-align: right !default; // Grid styles $ct-grid-color: rgba(0, 0, 0, 0.2) !default; diff --git a/package.json b/package.json index 5b270c65..e6307bff 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.3.0", + "version": "0.3.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 476e2da9..783b320e 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = {}; -Chartist.version = '0.3.0'; +Chartist.version = '0.3.1'; (function (window, document, Chartist) { 'use strict'; From 5f81fa2f72fc70fcd81bba1a4a4d8539659b9986 Mon Sep 17 00:00:00 2001 From: Faizan Shaharyar Date: Thu, 6 Nov 2014 11:47:13 +0100 Subject: [PATCH 059/593] fixed small typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc14be16..7a5fd6e1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ *Checkout the documentation site at http://gionkunz.github.io/chartist-js/* -*Checkout this lightening talk that gives you an overview of Chartist in 5 minutes https://www.youtube.com/watch?v=WdYzPhOB_c8* +*Checkout this lightning talk that gives you an overview of Chartist in 5 minutes https://www.youtube.com/watch?v=WdYzPhOB_c8* *Guest talk of the Chartist.js Guy at the Treehouse Show https://www.youtube.com/watch?v=h9oH0iDaZDQ&t=2m40s* From d350764dda8e4e18fe2d84d82a28c5cfb27bbce6 Mon Sep 17 00:00:00 2001 From: Drew Barontini Date: Mon, 10 Nov 2014 17:28:49 -0500 Subject: [PATCH 060/593] Add 'created' event to the 'createChart' function This adds a new event called 'created', which is triggered once a chart is finished drawing. This is created for all three charts, and it returns: - The type (e.g. 'Chartist.Bar') - The labels (in the case of Chartist.Pie, seriesGroup) - The created SVG element --- source/scripts/chartist.bar.js | 6 ++++++ source/scripts/chartist.line.js | 6 ++++++ source/scripts/chartist.pie.js | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index b9c15eca..7c435a7b 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -120,6 +120,12 @@ }); } } + + this.eventEmitter.emit('created', { + type: 'Chartist.Bar', + labels: labels, + svg: this.svg + }); } /** diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index e9166c45..9f045c88 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -173,6 +173,12 @@ } } } + + this.eventEmitter.emit('created', { + type: 'Chartist.Line', + labels: labels, + svg: this.svg + }); } /** diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index 8477a5e8..85131c68 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -185,6 +185,12 @@ // (except for last slice) startAngle = endAngle; } + + this.eventEmitter.emit('created', { + type: 'Chartist.Pie', + labels: seriesGroups, + svg: this.svg + }); } /** From 9ce93942c378735d6d0ea6e4b1a27de4fa6c385a Mon Sep 17 00:00:00 2001 From: Drew Barontini Date: Tue, 11 Nov 2014 05:58:10 -0500 Subject: [PATCH 061/593] Update 'created' event return object This changes the 'created' event returned object to send back: - The bounds - The chartRect - The options Additionally, it keeps the inserted SVG as a returned object. --- source/scripts/chartist.bar.js | 7 ++++--- source/scripts/chartist.line.js | 7 ++++--- source/scripts/chartist.pie.js | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 7c435a7b..9a427649 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -122,9 +122,10 @@ } this.eventEmitter.emit('created', { - type: 'Chartist.Bar', - labels: labels, - svg: this.svg + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options }); } diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 9f045c88..56826fa2 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -175,9 +175,10 @@ } this.eventEmitter.emit('created', { - type: 'Chartist.Line', - labels: labels, - svg: this.svg + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options }); } diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js index 85131c68..2edf763d 100644 --- a/source/scripts/chartist.pie.js +++ b/source/scripts/chartist.pie.js @@ -187,9 +187,9 @@ } this.eventEmitter.emit('created', { - type: 'Chartist.Pie', - labels: seriesGroups, - svg: this.svg + chartRect: chartRect, + svg: this.svg, + options: options }); } From 1fa0522927274211c3289d51b1c8fb68bb1b4478 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 3 Nov 2014 09:53:52 +0100 Subject: [PATCH 062/593] Refactored internal chartist reference --- source/scripts/chartist.base.js | 10 ++++++++-- source/scripts/chartist.core.js | 7 +++---- source/scripts/chartist.event.js | 2 +- source/scripts/chartist.svg.js | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js index 6d0206e9..c73068f3 100644 --- a/source/scripts/chartist.base.js +++ b/source/scripts/chartist.base.js @@ -71,7 +71,13 @@ this.eventEmitter = Chartist.EventEmitter(); this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); - window.addEventListener('resize', this.update.bind(this)); + if(this.container) { + this.container.__chartist__ = this; + } + + window.addEventListener('resize', function(){ + this.update(); + }.bind(this)); // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. @@ -102,4 +108,4 @@ supportsForeignObject: false }); -}(window, document, Chartist)); \ No newline at end of file +}(window, document, Chartist)); diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 783b320e..d3cb2f44 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -95,8 +95,8 @@ Chartist.version = '0.3.1'; height = height || '100%'; // If already contains our svg object we clear it, set width / height and return - if (container.chartistSvg !== undefined) { - svg = container.chartistSvg.attr({ + if (container.__chartist__ && container.__chartist__.svg) { + svg = container.__chartist__.svg.attr({ width: width, height: height }).removeAllClasses().addClass(className).attr({ @@ -116,7 +116,6 @@ Chartist.version = '0.3.1'; // Add the DOM node to our container container.appendChild(svg._node); - container.chartistSvg = svg; } return svg; @@ -679,4 +678,4 @@ Chartist.version = '0.3.1'; return d; }; -}(window, document, Chartist)); \ No newline at end of file +}(window, document, Chartist)); diff --git a/source/scripts/chartist.event.js b/source/scripts/chartist.event.js index dd8464e7..f1afa238 100644 --- a/source/scripts/chartist.event.js +++ b/source/scripts/chartist.event.js @@ -68,4 +68,4 @@ }; }; -}(window, document, Chartist)); \ No newline at end of file +}(window, document, Chartist)); diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index 3752f0da..ff6fe8c7 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -331,4 +331,4 @@ return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); }; -}(window, document, Chartist)); \ No newline at end of file +}(window, document, Chartist)); From 3997d7c3092f7366398da5380a7f1ce503ee8556 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 3 Nov 2014 09:54:48 +0100 Subject: [PATCH 063/593] Added delta analysis method in core for later use in progressive data updates --- source/scripts/chartist.core.js | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index d3cb2f44..dcdec4cc 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -637,6 +637,81 @@ Chartist.version = '0.3.1'; }; }; + //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas + /** + * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property + * where deltas for specific object properties can be found for the given object nesting level. For nested objects the + * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also + * contain a __delta__ property with the deltas of their level. + * + * @param {Object|Array} a Object that should be used to analyzed delta to object b + * @param {Object|Array} b The second object where the deltas from a should be analyzed + * @returns {Object} Delta descriptor object or null + */ + Chartist.deltaDescriptor = function(a, b) { + var summary = { + added: 0, + removed: 0, + modified: 0 + }; + + function findDeltasRecursively(a, b) { + var descriptor = { + __delta__: {} + }; + + // First check for removed and modified properties + Object.keys(a).forEach(function(property) { + if(!b.hasOwnProperty(property)) { + descriptor.__delta__[property] = { + type: 'remove', + property: property, + ours: a[property] + }; + summary.removed++; + } else { + if(typeof a[property] === 'object') { + var subDescriptor = findDeltasRecursively(a[property], b[property]); + if(subDescriptor) { + descriptor[property] = subDescriptor; + } + } else { + if(a[property] !== b[property]) { + descriptor.__delta__[property] = { + type: 'modify', + property: property, + ours: a[property], + theirs: b[property] + }; + summary.modified++; + } + } + } + }); + + // Check for added properties + Object.keys(b).forEach(function(property) { + if(!a.hasOwnProperty(property)) { + descriptor.__delta__[property] = { + type: 'added', + property: property, + theirs: b[property] + }; + summary.added++; + } + }); + + return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null; + } + + var delta = findDeltasRecursively(a, b); + if(delta) { + delta.__delta__.summary = summary; + } + + return delta; + }; + //http://schepers.cc/getting-to-the-point Chartist.catmullRom2bezier = function (crp, z) { var d = []; From 54daeaf9bfb8164754c8eccd1440b7383e42652d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 3 Nov 2014 09:58:21 +0100 Subject: [PATCH 064/593] Added possibility to add event handlers with asterisk that will be triggerd on all events including the event name in the cb function --- source/scripts/chartist.event.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/scripts/chartist.event.js b/source/scripts/chartist.event.js index f1afa238..2b495f7b 100644 --- a/source/scripts/chartist.event.js +++ b/source/scripts/chartist.event.js @@ -59,6 +59,13 @@ handler(data); }); } + + // Emit event to star event handlers + if(handlers['*']) { + handlers['*'].forEach(function(starHandler) { + starHandler(event, data); + }); + } } return { From c969511151584638aeb71cc9e7b4e3e0e3829bc7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 3 Nov 2014 09:59:54 +0100 Subject: [PATCH 065/593] Added animation function to SVG library --- source/scripts/chartist.svg.js | 40 +++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index ff6fe8c7..d004b7fe 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -28,7 +28,8 @@ var svgNs = 'http://www.w3.org/2000/svg', xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; + xhtmlNs = 'http://www.w3.org/1999/xhtml', + element = this; /** * Set attributes on the current SVG element of the wrapper you're currently working on. @@ -258,6 +259,39 @@ return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth; } + function animate(node, animations, eventEmitter) { + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + var animate = elem('animate', { + attributeName: attribute, + from: animations[attribute].from, + to: animations[attribute].to, + dur: animations[attribute].duration + }, null, node); + + if(eventEmitter) { + animate.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: element, + animate: animate, + params: animations[attribute] + }); + }); + } + + animate.addEventListener('endEvent', function handleBeginEvent() { + if(eventEmitter) { + eventEmitter.emit('animationBegin', { + element: element, + animate: animate, + params: animations[attribute] + }); + } + + remove(animate); + }); + }); + } + return { _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), _parent: parent, @@ -316,6 +350,10 @@ }, width: function() { return width(this._node); + }, + animate: function(animations) { + animate(this._node, animations); + return this; } }; }; From 31d083d95ecc55f26e7a4deb681df211d32c5cd5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 3 Nov 2014 10:01:15 +0100 Subject: [PATCH 066/593] Added possibility to pass DOM node to SVG constructor so you can wrap existing SVG nodes into a Chartist.Svg element --- source/scripts/chartist.svg.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index d004b7fe..7611cef4 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -293,7 +293,7 @@ } return { - _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), + _node: name instanceof Node ? name : elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), _parent: parent, parent: function() { return this._parent; From 9da63c1e96fe186996cae4dfe8ad9111f13416c7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 3 Nov 2014 20:11:26 +0100 Subject: [PATCH 067/593] Fixed svg recycling on re-creation --- source/scripts/chartist.core.js | 34 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index dcdec4cc..b3e0e67c 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -94,29 +94,21 @@ Chartist.version = '0.3.1'; width = width || '100%'; height = height || '100%'; - // If already contains our svg object we clear it, set width / height and return - if (container.__chartist__ && container.__chartist__.svg) { - svg = container.__chartist__.svg.attr({ - width: width, - height: height - }).removeAllClasses().addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' - }); - // Clear the draw if its already used before so we start fresh - svg.empty(); + svg = container.querySelector('svg'); + if(svg) { + container.removeChild(svg); + } - } else { - // Create svg object with width and height or use 100% as default - svg = Chartist.Svg('svg').attr({ - width: width, - height: height - }).addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' - }); + // Create svg object with width and height or use 100% as default + svg = Chartist.Svg('svg').attr({ + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); - // Add the DOM node to our container - container.appendChild(svg._node); - } + // Add the DOM node to our container + container.appendChild(svg._node); return svg; }; From 8e0a4262b6fdea2ef431fe8e0cb8ffbc4947635f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 15 Nov 2014 21:56:57 +0100 Subject: [PATCH 068/593] Fixed resize listener detach that wasn't working properly --- source/scripts/chartist.base.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js index c73068f3..c0b057e1 100644 --- a/source/scripts/chartist.base.js +++ b/source/scripts/chartist.base.js @@ -28,7 +28,7 @@ * @memberof Chartist.Base */ function detach() { - window.removeEventListener('resize', this.update); + window.removeEventListener('resize', this.resizeListener); this.optionsProvider.removeMediaQueryListeners(); } @@ -70,14 +70,20 @@ this.responsiveOptions = responsiveOptions; this.eventEmitter = Chartist.EventEmitter(); this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); + this.resizeListener = function resizeListener(){ + this.update(); + }.bind(this); if(this.container) { + // If chartist was already initialized in this container we are detaching all event listeners first + if(this.container.__chartist__) { + this.container.__chartist__.detach(); + } + this.container.__chartist__ = this; } - window.addEventListener('resize', function(){ - this.update(); - }.bind(this)); + window.addEventListener('resize', this.resizeListener); // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. From c04dbb71d193c35a3388b6b785d5cca3630354bc Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 15 Nov 2014 22:21:33 +0100 Subject: [PATCH 069/593] If highest data value is exactly on grid line we don't need to recalculate the steps --- source/scripts/chartist.core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index b3e0e67c..9416d871 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -303,7 +303,7 @@ Chartist.version = '0.3.1'; newMin += bounds.step; } - if (i - bounds.step > bounds.high) { + if (i - bounds.step >= bounds.high) { newMax -= bounds.step; } } From 027a1247986ab163e3233e26a0fb95c417f80f01 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 14:41:28 +0100 Subject: [PATCH 070/593] Refactored Chartist.Svg to use Chartist.Class --- source/scripts/chartist.core.js | 2 +- source/scripts/chartist.svg.js | 573 +++++++++--------- .../example-bar-with-circle-modify-drawing.js | 4 +- .../examples/example-line-modify-drawing.js | 4 +- test/spec/spec-svg.js | 20 +- 5 files changed, 291 insertions(+), 312 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 9416d871..3190aa66 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -100,7 +100,7 @@ Chartist.version = '0.3.1'; } // Create svg object with width and height or use 100% as default - svg = Chartist.Svg('svg').attr({ + svg = new Chartist.Svg('svg').attr({ width: width, height: height }).addClass(className).attr({ diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index 7611cef4..ab14aa7d 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -7,6 +7,10 @@ (function(window, document, Chartist) { 'use strict'; + var svgNs = 'http://www.w3.org/2000/svg', + xmlNs = 'http://www.w3.org/2000/xmlns/', + xhtmlNs = 'http://www.w3.org/1999/xhtml'; + Chartist.xmlNs = { qualifiedName: 'xmlns:ct', prefix: 'ct', @@ -24,339 +28,314 @@ * @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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ - Chartist.Svg = function(name, attributes, className, parent, insertFirst) { - - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml', - element = this; - - /** - * Set attributes on the current SVG element of the wrapper you're currently working on. - * - * @memberof Chartist.Svg - * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {Object} The current wrapper object will be returned so it can be used for chaining. - */ - function attr(node, attributes, ns) { - Object.keys(attributes).forEach(function(key) { - // If the attribute value is undefined we can skip this one - if(attributes[key] === undefined) { - return; - } + function Svg(name, attributes, className, parent, insertFirst) { + this._node = document.createElementNS(svgNs, name); - if(ns) { - node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); - } else { - node.setAttribute(key, attributes[key]); - } - }); + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + } - return node; + if(attributes) { + this.attr(attributes); } - /** - * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. - * - * @memberof Chartist.Svg - * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @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 - * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data - */ - function elem(name, attributes, className, parentNode, insertFirst) { - var node = document.createElementNS(svgNs, name); - - // If this is an SVG element created then custom namespace - if(name === 'svg') { - node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); - } + if(className) { + this.addClass(className); + } - if(parentNode) { - if(insertFirst && parentNode.firstChild) { - parentNode.insertBefore(node, parentNode.firstChild); - } else { - parentNode.appendChild(node); - } + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); } - if(attributes) { - attr(node, attributes); + this._parent = parent; + } + } + + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Chartist.Svg + * @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. + * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @returns {Object} The current wrapper object will be returned so it can be used for chaining. + */ + function attr(attributes, ns) { + Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; } - if(className) { - addClass(node, className); + if(ns) { + this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + } else { + this._node.setAttribute(key, attributes[key]); } + }.bind(this)); + + return this; + } + + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + function elem(name, attributes, className, insertFirst) { + return new Chartist.Svg(name, attributes, className, this, insertFirst); + } - return node; + /** + * 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. + * + * @memberof Chartist.Svg + * @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 + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @returns {Object} New wrapper object that wraps the foreignObject element + */ + function foreignObject(content, attributes, className, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; } - /** - * 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. - * - * @memberof Chartist.Svg - * @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 - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Object} New wrapper object that wraps the foreignObject element - */ - function foreignObject(content, attributes, className, parent, insertFirst) { - // If content is string then we convert it to DOM - // TODO: Handle case where content is not a string nor a DOM Node - if(typeof content === 'string') { - var container = document.createElement('div'); - container.innerHTML = content; - content = container.firstChild; - } + // Adding namespace to content element + content.setAttribute('xmlns', xhtmlNs); - // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = this.elem('foreignObject', attributes, className, insertFirst); - // Creating the foreignObject without required extension attribute (as described here - // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = parent.elem('foreignObject', attributes, className, insertFirst); + // Add content to foreignObjectElement + fnObj._node.appendChild(content); - // Add content to foreignObjectElement - fnObj._node.appendChild(content); + return fnObj; + } - return fnObj; - } + /** + * This method adds a new text element to the current Chartist.Svg wrapper. + * + * @memberof Chartist.Svg + * @param {String} t The text that should be added to the text element that is created + * @returns {Object} The same wrapper object that was used to add the newly created element + */ + function text(t) { + this._node.appendChild(document.createTextNode(t)); + return this; + } - /** - * This method adds a new text element to the current Chartist.Svg wrapper. - * - * @memberof Chartist.Svg - * @param {String} t The text that should be added to the text element that is created - * @returns {Object} The same wrapper object that was used to add the newly created element - */ - function text(node, t) { - node.appendChild(document.createTextNode(t)); + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Chartist.Svg + * @returns {Object} The same wrapper object that got emptied + */ + function empty() { + while (this._node.firstChild) { + this._node.removeChild(this._node.firstChild); } - /** - * This method will clear all child nodes of the current wrapper object. - * - * @memberof Chartist.Svg - * @returns {Object} The same wrapper object that got emptied - */ - function empty(node) { - while (node.firstChild) { - node.removeChild(node.firstChild); - } - } + return this; + } - /** - * 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. - * - * @memberof Chartist.Svg - * @returns {Object} The parent wrapper object of the element that got removed - */ - function remove(node) { - node.parentNode.removeChild(node); - } + /** + * 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. + * + * @memberof Chartist.Svg + * @returns {Object} The parent wrapper object of the element that got removed + */ + function remove() { + this._node.parentNode.removeChild(this._node); + return this._parent; + } - /** - * This method will replace the element with a new element that can be created outside of the current DOM. - * - * @memberof Chartist.Svg - * @param {Object} newElement The new wrapper object that will be used to replace the current wrapper object - * @returns {Object} The wrapper of the new element - */ - function replace(node, newChild) { - node.parentNode.replaceChild(newChild, node); - } + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Chartist.Svg + * @param {Object} newElement The new Chartist.Svg object that will be used to replace the current wrapper object + * @returns {Object} The wrapper of the new element + */ + function replace(newElement) { + this._node.parentNode.replaceChild(newElement._node, this._node); + newElement._parent = this._parent; + this._parent = null; + return newElement; + } - /** - * This method will append an element to the current element as a child. - * - * @memberof Chartist.Svg - * @param {Object} element The element that should be added as a child - * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Object} The wrapper of the appended object - */ - function append(node, child, insertFirst) { - if(insertFirst && node.firstChild) { - node.insertBefore(child, node.firstChild); - } else { - node.appendChild(child); - } + /** + * This method will append an element to the current element as a child. + * + * @memberof Chartist.Svg + * @param {Object} element The Chartist.Svg element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @returns {Object} The wrapper of the appended object + */ + function append(element, insertFirst) { + if(insertFirst && this._node.firstChild) { + this._node.insertBefore(element._node, this._node.firstChild); + } else { + this._node.appendChild(element._node); } - /** - * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. - * - * @memberof Chartist.Svg - * @returns {Array} A list of classes or an empty array if there are no classes on the current element - */ - function classes(node) { - return node.getAttribute('class') ? node.getAttribute('class').trim().split(/\s+/) : []; - } + return this; + } - /** - * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element - */ - function addClass(node, names) { - node.setAttribute('class', - classes(node) - .concat(names.trim().split(/\s+/)) - .filter(function(elem, pos, self) { - return self.indexOf(elem) === pos; - }).join(' ') - ); - } + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Chartist.Svg + * @returns {Array} A list of classes or an empty array if there are no classes on the current element + */ + function classes() { + return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; + } - /** - * Removes one or a space separated list of classes from the current element. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element - */ - function removeClass(node, names) { - var removedClasses = names.trim().split(/\s+/); - - node.setAttribute('class', classes(node).filter(function(name) { - return removedClasses.indexOf(name) === -1; - }).join(' ')); - } + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ + function addClass(names) { + this._node.setAttribute('class', + this.classes(this._node) + .concat(names.trim().split(/\s+/)) + .filter(function(elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ') + ); + + return this; + } - /** - * Removes all classes from the current element. - * - * @memberof Chartist.Svg - * @returns {Object} The wrapper of the current element - */ - function removeAllClasses(node) { - node.setAttribute('class', ''); - } + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ + function removeClass(names) { + var removedClasses = names.trim().split(/\s+/); - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Svg - * @return {Number} The elements height in pixels - */ - function height(node) { - return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight; - } + this._node.setAttribute('class', this.classes(this._node).filter(function(name) { + return removedClasses.indexOf(name) === -1; + }).join(' ')); - /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @return {Number} The elements width in pixels - */ - function width(node) { - return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth; - } + return this; + } - function animate(node, animations, eventEmitter) { - Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { - var animate = elem('animate', { - attributeName: attribute, - from: animations[attribute].from, - to: animations[attribute].to, - dur: animations[attribute].duration - }, null, node); + /** + * Removes all classes from the current element. + * + * @memberof Chartist.Svg + * @returns {Object} The wrapper of the current element + */ + function removeAllClasses() { + this._node.setAttribute('class', ''); + } + /** + * Get element height with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Svg + * @return {Number} The elements height in pixels + */ + function height() { + return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; + } + + /** + * Get element width with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + function width() { + return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + } + + function animate(animations, eventEmitter) { + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + // Adding fill: freeze if not specified + animations[attribute].fill = animations[attribute].fill || 'freeze'; + + var animate = this.elem('animate', Chartist.extend({ + attributeName: attribute + }, animations[attribute])); + + // Animated attribute is already set to the animation from value for proper delayed animations + var attributeProperties = {}; + attributeProperties[attribute] = animations[attribute].from; + this.attr(attributeProperties); + + if(eventEmitter) { + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animations[attribute] + }); + }.bind(this)); + } + + animate._node.addEventListener('endEvent', function handleEndEvent() { if(eventEmitter) { - animate.addEventListener('beginEvent', function handleBeginEvent() { - eventEmitter.emit('animationBegin', { - element: element, - animate: animate, - params: animations[attribute] - }); + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animations[attribute] }); } - animate.addEventListener('endEvent', function handleBeginEvent() { - if(eventEmitter) { - eventEmitter.emit('animationBegin', { - element: element, - animate: animate, - params: animations[attribute] - }); - } - - remove(animate); - }); - }); - } - - return { - _node: name instanceof Node ? name : elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), - _parent: parent, - parent: function() { - return this._parent; - }, - attr: function(attributes, ns) { - attr(this._node, attributes, ns); - return this; - }, - empty: function() { - empty(this._node); - return this; - }, - remove: function() { - remove(this._node); - return this.parent(); - }, - replace: function(newElement) { - newElement._parent = this._parent; - replace(this._node, newElement._node); - return newElement; - }, - append: function(element, insertFirst) { - element._parent = this; - append(this._node, element._node, insertFirst); - return element; - }, - elem: function(name, attributes, className, insertFirst) { - return Chartist.Svg(name, attributes, className, this, insertFirst); - }, - foreignObject: function(content, attributes, className, insertFirst) { - return foreignObject(content, attributes, className, this, insertFirst); - }, - text: function(t) { - text(this._node, t); - return this; - }, - addClass: function(names) { - addClass(this._node, names); - return this; - }, - removeClass: function(names) { - removeClass(this._node, names); - return this; - }, - removeAllClasses: function() { - removeAllClasses(this._node); - return this; - }, - classes: function() { - return classes(this._node); - }, - height: function() { - return height(this._node); - }, - width: function() { - return width(this._node); - }, - animate: function(animations) { - animate(this._node, animations); - return this; - } - }; - }; + // Set animated attribute to current animated value + attributeProperties[attribute] = animations[attribute].to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + }.bind(this)); + + }.bind(this)); + + return this; + } + + Chartist.Svg = Chartist.Class.extend({ + constructor: Svg, + attr: attr, + elem: elem, + foreignObject: foreignObject, + text: text, + empty: empty, + remove: remove, + replace: replace, + append: append, + classes: classes, + addClass: addClass, + removeClass: removeClass, + removeAllClasses: removeAllClasses, + height: height, + width: width, + animate: animate + }); /** * 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. diff --git a/source/site/examples/example-bar-with-circle-modify-drawing.js b/source/site/examples/example-bar-with-circle-modify-drawing.js index ed304473..a5b71c4b 100644 --- a/source/site/examples/example-bar-with-circle-modify-drawing.js +++ b/source/site/examples/example-bar-with-circle-modify-drawing.js @@ -19,10 +19,10 @@ chart.on('draw', function(data) { // If this draw event is of type bar we can use the data to create additional content if(data.type === 'bar') { // We use the group element of the current series to append a simple circle with the bar peek coordinates and a circle radius that is depending on the value - data.group.append(Chartist.Svg('circle', { + data.group.append(new Chartist.Svg('circle', { cx: data.x2, cy: data.y2, r: Math.abs(data.value) * 2 + 5 }, 'ct-slice')); } -}); \ No newline at end of file +}); diff --git a/source/site/examples/example-line-modify-drawing.js b/source/site/examples/example-line-modify-drawing.js index d21fbb3b..32785ab1 100644 --- a/source/site/examples/example-line-modify-drawing.js +++ b/source/site/examples/example-line-modify-drawing.js @@ -10,7 +10,7 @@ chart.on('draw', function(data) { // If the draw event was triggered from drawing a point on the line chart if(data.type === 'point') { // We are creating a new path SVG element that draws a triangle around the point coordinates - var triangle = Chartist.Svg('path', { + var triangle = new Chartist.Svg('path', { d: ['M', data.x, data.y - 15, @@ -27,4 +27,4 @@ chart.on('draw', function(data) { // With data.element we get the Chartist SVG wrapper and we can replace the original point drawn by Chartist with our newly created triangle data.element.replace(triangle); } -}); \ No newline at end of file +}); diff --git a/test/spec/spec-svg.js b/test/spec/spec-svg.js index 09959834..4e5fea34 100644 --- a/test/spec/spec-svg.js +++ b/test/spec/spec-svg.js @@ -15,7 +15,7 @@ describe('Chartist SVG', function () { }); it('should create a valid svg dom element', function () { - var svg = window.Chartist.Svg('svg'); + var svg = new window.Chartist.Svg('svg'); expect(svg).toBeDefined(); expect(svg._node).toBeDefined(); @@ -23,7 +23,7 @@ describe('Chartist SVG', function () { }); it('should create a valid svg dom element with attributes', function () { - var svg = window.Chartist.Svg('svg', { + var svg = new window.Chartist.Svg('svg', { width: '100%', height: '100%' }); @@ -36,7 +36,7 @@ describe('Chartist SVG', function () { }); it('should create nested objects with attributes', function () { - var svg = window.Chartist.Svg('svg'); + var svg = new window.Chartist.Svg('svg'); svg.elem('g').elem('g').elem('circle', { cx: 100, cy: 100, @@ -51,7 +51,7 @@ describe('Chartist SVG', function () { }); it('should allow to set attributes manually', function () { - var svg = window.Chartist.Svg('svg'); + var svg = new window.Chartist.Svg('svg'); svg.elem('circle').attr({ cx: 100, cy: 100, @@ -66,7 +66,7 @@ describe('Chartist SVG', function () { }); it('should clear on each nesting level', function () { - var svg = window.Chartist.Svg('svg'); + var svg = new window.Chartist.Svg('svg'); var group = svg.elem('g'); group.elem('circle'); group.elem('circle'); @@ -83,7 +83,7 @@ describe('Chartist SVG', function () { }); it('should allow to remove a certain element', function () { - var svg = window.Chartist.Svg('svg'); + var svg = new window.Chartist.Svg('svg'); var text = svg.elem('text'); expect(svg._node).toBeDefined(); @@ -95,7 +95,7 @@ describe('Chartist SVG', function () { }); it('should allow to write text content into elements', function () { - var svg = window.Chartist.Svg('svg'); + var svg = new window.Chartist.Svg('svg'); svg.elem('text').text('Hello World'); expect(svg._node).toBeDefined(); @@ -106,7 +106,7 @@ describe('Chartist SVG', function () { }); it('should allow to add and remove classes on elements', function () { - var svg = window.Chartist.Svg('svg') + var svg = new window.Chartist.Svg('svg') .addClass('test-class-1') .addClass('test-class-2') // Should not allow duplicates @@ -130,7 +130,7 @@ describe('Chartist SVG', function () { }); it('should allow to travers up in the fluent API chain and set attributes on the way', function () { - var svg = window.Chartist.Svg('svg'); + var svg = new window.Chartist.Svg('svg'); svg.elem('g').elem('g').elem('g').elem('circle') .parent().attr({ transform: 'rotate(10 10 10)' @@ -159,4 +159,4 @@ describe('Chartist SVG', function () { expect(svg._node.firstChild.firstChild.firstChild).toBeDefined(); expect(svg._node.firstChild.firstChild.firstChild.attributes.transform.textContent).toBe('rotate(10 10 10)'); }); -}); \ No newline at end of file +}); From fc8e0099d045aee32d78baf150fbfcc3b5473cce Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 14:42:41 +0100 Subject: [PATCH 071/593] Added supportsAnimations property to base chart class for convenience --- source/scripts/chartist.base.js | 1 + 1 file changed, 1 insertion(+) diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js index c0b057e1..4b7c5da7 100644 --- a/source/scripts/chartist.base.js +++ b/source/scripts/chartist.base.js @@ -70,6 +70,7 @@ this.responsiveOptions = responsiveOptions; this.eventEmitter = Chartist.EventEmitter(); this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); + this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); this.resizeListener = function resizeListener(){ this.update(); }.bind(this); From 0601e00f51502daf3ba0fc68da79dcdd0fe869b7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 14:43:05 +0100 Subject: [PATCH 072/593] Fixed class dox comments --- source/scripts/chartist.class.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/scripts/chartist.class.js b/source/scripts/chartist.class.js index 42171e66..10c0c603 100644 --- a/source/scripts/chartist.class.js +++ b/source/scripts/chartist.class.js @@ -53,7 +53,7 @@ * var banana = new Banana(20, 40); * console.log('banana instanceof Fruit', banana instanceof Fruit); * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); * console.log(banana.sugar); * console.log(banana.eat().sugar); * console.log(banana.color); @@ -121,7 +121,7 @@ * var banana = new Banana(20, 40); * console.log('banana instanceof Fruit', banana instanceof Fruit); * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); * console.log(banana.sugar); * console.log(banana.eat().sugar); * console.log(banana.color); @@ -163,7 +163,7 @@ * var banana = new Banana(20, 40); * console.log('banana instanceof Fruit', banana instanceof Fruit); * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); * console.log(banana.sugar); * console.log(banana.eat().sugar); * console.log(banana.color); @@ -214,4 +214,4 @@ cloneDefinitions: cloneDefinitions }; -}(window, document, Chartist)); \ No newline at end of file +}(window, document, Chartist)); From fa0779877323f5fd0095cea2ac0c8ebcf521ade5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 14:54:00 +0100 Subject: [PATCH 073/593] Including event when line and area is drawn --- source/scripts/chartist.line.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 56826fa2..9347cd7c 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -157,19 +157,35 @@ areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); // Create the new path for the area shape with the area class from the options - seriesGroups[i].elem('path', { + var area = seriesGroups[i].elem('path', { d: areaPathElements.join('') }, options.classNames.area, true).attr({ 'values': normalizedData[i] }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: area + }); } if(options.showLine) { - seriesGroups[i].elem('path', { + var line = seriesGroups[i].elem('path', { d: pathElements.join('') }, options.classNames.line, true).attr({ 'values': normalizedData[i] }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: line + }); } } } From d18b642292638819010dc7af6782be3b406f4e53 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 22:59:21 +0100 Subject: [PATCH 074/593] Changed default scaleMinSpace to 20 to be more mobile friendly --- source/scripts/chartist.bar.js | 2 +- source/scripts/chartist.line.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index 9a427649..d2848696 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -27,7 +27,7 @@ showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 30 + scaleMinSpace: 20 }, width: undefined, height: undefined, diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 9347cd7c..c1b0ff91 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -29,7 +29,7 @@ showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 30 + scaleMinSpace: 20 }, width: undefined, height: undefined, From faf577c57aba6b57ae774a3272f16a131f8026ab Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 23:02:10 +0100 Subject: [PATCH 075/593] Renamed getPixel method to stripUnit and added ensureUnit as convenience functions for user input --- source/scripts/chartist.core.js | 37 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 3190aa66..07677910 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -54,17 +54,34 @@ Chartist.version = '0.3.1'; }; /** - * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified. + * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. * - * @param {String|Number} length - * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel + * @memberof Chartist.Core + * @param {String|Number} value + * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel + */ + Chartist.stripUnit = function(value) { + if(typeof value === 'string') { + value = value.replace(/[^0-9\+-\.]/, ''); + } + + return +value; + }; + + /** + * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {Number} value + * @param {String} unit + * @returns {String} Returns the passed number value with unit. */ - Chartist.getPixelLength = function(length) { - if(typeof length === 'string') { - length = length.replace(/px/i, ''); + Chartist.ensureUnit = function(value, unit) { + if(typeof value === 'number') { + value = value + unit; } - return +length; + return value; }; /** @@ -195,7 +212,7 @@ Chartist.version = '0.3.1'; * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); + return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); }; /** @@ -352,8 +369,8 @@ Chartist.version = '0.3.1'; return { x1: options.chartPadding + yOffset, - y1: Math.max((Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max((Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), + y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), y2: options.chartPadding, width: function () { return this.x2 - this.x1; From bcf51d73df97c39b6436d1ef87f7f872c73fb9a1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 23:02:28 +0100 Subject: [PATCH 076/593] Fixed bug with line area base --- source/scripts/chartist.line.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index c1b0ff91..8a0a994a 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -144,7 +144,7 @@ if(options.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); + var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); // If we need to draw area shapes we just make a copy of our pathElements SVG path array var areaPathElements = pathElements.slice(); From da9982dbdef4c8addb5ecc724eb8dcb4bb839363 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 23:04:21 +0100 Subject: [PATCH 077/593] Refactored animation method to provide more user friendly API --- source/scripts/chartist.svg.js | 183 +++++++++++++++++++++++++++------ 1 file changed, 149 insertions(+), 34 deletions(-) diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index ab14aa7d..969f46a7 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -273,45 +273,126 @@ return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; } - function animate(animations, eventEmitter) { + /** + * 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 values specifying a cubic Bézier curve. + * **An animations object could look like this:** + * ```javascript + * element.animate({ + * opacity: { + * dur: 1000, + * from: 0, + * to: 1 + * }, + * x1: { + * dur: '1000ms', + * from: 100, + * to: 200, + * easing: 'easeOutQuart' + * }, + * y1: { + * dur: '2s', + * from: 0, + * to: 100 + * } + * }); + * ``` + * **Automatic unit conversion** + * 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. + * **Guided mode** + * 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. 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. + * If guided mode is enabled the following behavior is added: + * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - The animate element will be forced to use `fill="freeze"` + * - After the animation the element attribute value will be set to the `to` value of the animation + * - The animate element is deleted from the DOM + * + * @memberof Chartist.Svg + * @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. + * @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. + * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. + * @returns {Object} The current element where the animation was added + */ + function animate(animations, guided, eventEmitter) { + if(guided === undefined) { + guided = true; + } + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { - // Adding fill: freeze if not specified - animations[attribute].fill = animations[attribute].fill || 'freeze'; - - var animate = this.elem('animate', Chartist.extend({ - attributeName: attribute - }, animations[attribute])); - - // Animated attribute is already set to the animation from value for proper delayed animations - var attributeProperties = {}; - attributeProperties[attribute] = animations[attribute].from; - this.attr(attributeProperties); - - if(eventEmitter) { - animate._node.addEventListener('beginEvent', function handleBeginEvent() { - eventEmitter.emit('animationBegin', { - element: this, - animate: animate._node, - params: animations[attribute] - }); - }.bind(this)); - } - animate._node.addEventListener('endEvent', function handleEndEvent() { + function createAnimate(animationDefinition, guided) { + var attributeProperties = {}, + animate, + easing; + + // Check if an easing is specified in the definition object and delete it from the object as it will not + // be part of the animate element attributes. + if(animationDefinition.easing) { + // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object + easing = animationDefinition.easing instanceof Array ? + animationDefinition.easing : + Chartist.Svg.Easing[animationDefinition.easing]; + delete animationDefinition.easing; + } + + // Adding "fill: freeze" if we are in guided mode and set initial attribute values + if(guided) { + animationDefinition.fill = 'freeze'; + // Animated property on our element should already be set to the animation from value in guided mode + attributeProperties[attribute] = animationDefinition.from; + this.attr(attributeProperties); + } + + if(easing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = easing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); + + animate = this.elem('animate', Chartist.extend({ + attributeName: attribute + }, animationDefinition)); + if(eventEmitter) { - eventEmitter.emit('animationEnd', { - element: this, - animate: animate._node, - params: animations[attribute] - }); + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animationDefinition + }); + }.bind(this)); } - // Set animated attribute to current animated value - attributeProperties[attribute] = animations[attribute].to; - this.attr(attributeProperties); - // Remove the animate element as it's no longer required - animate.remove(); - }.bind(this)); + animate._node.addEventListener('endEvent', function handleEndEvent() { + if(eventEmitter) { + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animationDefinition + }); + } + + if(guided) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this)); + } + + // If current attribute is an array of definition objects we create an animate for each and disable guided mode + if(animations[attribute] instanceof Array) { + animations[attribute].forEach(function(animationDefinition) { + createAnimate.bind(this)(animationDefinition, false); + }.bind(this)); + } else { + createAnimate.bind(this)(animations[attribute], guided); + } }.bind(this)); @@ -348,4 +429,38 @@ return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); }; + /** + * 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. + * + * @memberof Chartist.Svg + */ + var easingCubicBeziers = { + easeInSine: [0.47, 0, 0.745, 0.715], + easeOutSine: [0.39, 0.575, 0.565, 1], + easeInOutSine: [0.445, 0.05, 0.55, 0.95], + easeInQuad: [0.55, 0.085, 0.68, 0.53], + easeOutQuad: [0.25, 0.46, 0.45, 0.94], + easeInOutQuad: [0.455, 0.03, 0.515, 0.955], + easeInCubic: [0.55, 0.055, 0.675, 0.19], + easeOutCubic: [0.215, 0.61, 0.355, 1], + easeInOutCubic: [0.645, 0.045, 0.355, 1], + easeInQuart: [0.895, 0.03, 0.685, 0.22], + easeOutQuart: [0.165, 0.84, 0.44, 1], + easeInOutQuart: [0.77, 0, 0.175, 1], + easeInQuint: [0.755, 0.05, 0.855, 0.06], + easeOutQuint: [0.23, 1, 0.32, 1], + easeInOutQuint: [0.86, 0, 0.07, 1], + easeInExpo: [0.95, 0.05, 0.795, 0.035], + easeOutExpo: [0.19, 1, 0.22, 1], + easeInOutExpo: [1, 0, 0, 1], + easeInCirc: [0.6, 0.04, 0.98, 0.335], + easeOutCirc: [0.075, 0.82, 0.165, 1], + easeInOutCirc: [0.785, 0.135, 0.15, 0.86], + easeInBack: [0.6, -0.28, 0.735, 0.045], + easeOutBack: [0.175, 0.885, 0.32, 1.275], + easeInOutBack: [0.68, -0.55, 0.265, 1.55] + }; + + Chartist.Svg.Easing = easingCubicBeziers; + }(window, document, Chartist)); From 446539b8a0243b719fb8bd2b8c93dae9af5c7fb4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 23:04:44 +0100 Subject: [PATCH 078/593] Refactored site styles --- source/site/layouts/default.hbs | 1 - source/styles/site/_api-doc.scss | 8 +++++++- source/styles/site/_base.scss | 4 +--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/site/layouts/default.hbs b/source/site/layouts/default.hbs index b83e88e8..afd2207a 100644 --- a/source/site/layouts/default.hbs +++ b/source/site/layouts/default.hbs @@ -14,7 +14,6 @@ - diff --git a/source/styles/site/_api-doc.scss b/source/styles/site/_api-doc.scss index c38b6907..61f62d59 100644 --- a/source/styles/site/_api-doc.scss +++ b/source/styles/site/_api-doc.scss @@ -29,6 +29,12 @@ .description { margin-top: 1em; margin-bottom: 2em; + + strong { + display: inline-block; + padding-top: 1em; + padding-bottom: 0.5em; + } } .member-title { @@ -72,4 +78,4 @@ pre { margin: 0 -10px; } -} \ No newline at end of file +} diff --git a/source/styles/site/_base.scss b/source/styles/site/_base.scss index 754b3907..7e23e031 100644 --- a/source/styles/site/_base.scss +++ b/source/styles/site/_base.scss @@ -31,10 +31,8 @@ a { ul { padding: 0; - &.list { list-style: disc outside none; padding-left: 1em; - } } pre { @@ -125,4 +123,4 @@ table { thead th { padding: 0.8em 1em; } -} \ No newline at end of file +} From 916dd67c52389a2399b38e9fe8187b1855e2ea03 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 23:05:16 +0100 Subject: [PATCH 079/593] Added SVG animation documentation and examples --- source/site/data/pages/examples.yml | 10 ++ source/site/data/pages/getting-started.yml | 34 +++++ source/site/data/pages/index.yml | 44 +++++- .../examples/example-line-svg-animation.js | 127 ++++++++++++++++++ .../examples/example-simple-svg-animation.js | 63 +++++++++ 5 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 source/site/examples/example-line-svg-animation.js create mode 100644 source/site/examples/example-simple-svg-animation.js diff --git a/source/site/data/pages/examples.yml b/source/site/data/pages/examples.yml index 94ce92f0..3fdb6a7c 100644 --- a/source/site/data/pages/examples.yml +++ b/source/site/data/pages/examples.yml @@ -60,6 +60,16 @@ sections: provide a high level of separation of the concerns. However, sometimes you probably would like to use different shapes or even images for your charts. One way to achieve this is by using the draw events and replace or add custom SVG shapes. + - type: live-example + data: + title: Advanced SMIL Animations + level: 4 + id: example-line-svg-animation + classes: ct-golden-section + intro: > + Chartist provides a simple API to animate the elements on the Chart using SMIL. Usually you can achieve most + animation with CSS3 animations but in some cases you'd like to animate SVG properties that are not available + in CSS. - title: Bar chart examples level: 3 items: diff --git a/source/site/data/pages/getting-started.yml b/source/site/data/pages/getting-started.yml index 81c1f7cf..bd0d660e 100644 --- a/source/site/data/pages/getting-started.yml +++ b/source/site/data/pages/getting-started.yml @@ -396,3 +396,37 @@ sections: id: behavior-with-jquery classes: ct-golden-section show-code-button: Show code + + - type: sub-section + data: + title: Animations using Chartist.Svg + level: 4 + items: + - type: text + data: + text: > + Usually we recommend using CSS for animations as it's closer to a clean separation of concerns. + However, sometimes you would want to animate SVG properties that are not available in CSS to animate. + For this purpose we have added a simple but powerful animation API that allows you to create SMIL + animations in a more convenient way. + - type: text + data: + text: > + In combination with the draw events of Chartist the animations are a very powerful and + flexible tool. You can intercept almost any step in chartist and if there is an SVG element + involved you can animate it using + Chartist.Svg.animate. + - type: text + data: + text: > + The following simple example shows you how to created a delayed fade in effect for the a scatter chart. + You can also edit the example to play around with the settings. + + - type: live-example + data: + title: Some SVG Animations can only be done with SMIL + level: 5 + id: example-simple-svg-animation + classes: ct-golden-section + intro: > + Edit this example to figure out how to tweak animations. The force is strong in you young padawan! diff --git a/source/site/data/pages/index.yml b/source/site/data/pages/index.yml index c55a8224..d9d9e0df 100644 --- a/source/site/data/pages/index.yml +++ b/source/site/data/pages/index.yml @@ -132,6 +132,41 @@ sections: - name: iOS Safari 7 status: supported text: Supported + - name: SVG Animations with SMIL + browsers: + - name: IE9 + status: not-supported + text: Not supported + - name: IE10 + status: not-supported + text: Not supported + - name: IE11 + status: not-supported + text: Not supported + - name: Firefox 31 + status: supported + text: Supported + - name: Chrome 35 + status: supported + text: Supported + - name: Safari 7 + status: supported + text: Supported + - name: Safari 8 + status: supported + text: Supported + - name: Andorid 4.3 + status: supported + text: Supported + - name: Andorid 4.4 + status: supported + text: Supported + - name: iOS Safari 6 + status: supported + text: Supported + - name: iOS Safari 7 + status: supported + text: Supported - name: Reponsive Options Override browsers: - name: IE9* @@ -184,17 +219,20 @@ sections: data: text: Specifying the style of your chart in CSS is not only cleaner but also enables you to use awesome CSS animations and transitions to be applied to your SVG elements! - - title: New bar chart type! + - title: Crazy Animations with SMIL! level: 3 items: - type: example-chart data: - id: example-simple-bar + id: example-line-svg-animation classes: ct-golden-section side-notes: - type: text data: - text: We are constantly working on enhancements of our existing charts and adding new chart types. While we only have two chart types currently available you can customize them to your own needs while getting a huge vaiarity of configurations and designs. + text: > + Almost limitless animation possibilities with the Chartist.Svg animation API. Checkout the + advanced getting stated guide about SVG + animations with SMIL. - title: Responsive charts configuration level: 3 diff --git a/source/site/examples/example-line-svg-animation.js b/source/site/examples/example-line-svg-animation.js new file mode 100644 index 00000000..0e344de6 --- /dev/null +++ b/source/site/examples/example-line-svg-animation.js @@ -0,0 +1,127 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], + series: [ + [12, 9, 7, 8, 5, 4, 6, 2, 3, 3, 4, 6], + [4, 5, 3, 7, 3, 5, 5, 3, 4, 4, 5, 5], + [5, 3, 4, 5, 6, 3, 3, 4, 5, 6, 3, 4], + [3, 4, 5, 6, 7, 6, 4, 5, 6, 7, 6, 3] + ] +}, { + low: 0 +}); + +// Let's put a sequence number aside so we can use it in the event callbacks +var seq = 0, + delays = 80, + durations = 500; + +// Once the chart is fully created we reset the sequence +chart.on('created', function() { + seq = 0; +}); + +// On each drawn element by Chartist we use the Chartist.Svg API to trigger SMIL animations +chart.on('draw', function(data) { + seq++; + + if(data.type === 'line') { + // If the drawn element is a line we do a simple opacity fade in. This could also be achieved using CSS3 animations. + data.element.animate({ + opacity: { + // The delay when we like to start the animation + begin: seq * delays + 1000, + // Duration of the animation + dur: durations, + // The value where the animation should start + from: 0, + // The value where it should end + to: 1 + } + }); + } else if(data.type === 'label' && data.axis === 'x') { + data.element.animate({ + y: { + begin: seq * delays, + dur: durations, + from: data.y + 100, + to: data.y, + // We can specify an easing function from Chartist.Svg.Easing + easing: 'easeInOutBack' + } + }); + } else if(data.type === 'label' && data.axis === 'y') { + data.element.animate({ + x: { + begin: seq * delays, + dur: durations, + from: data.x - 100, + to: data.x, + easing: 'easeInOutBack' + } + }); + } else if(data.type === 'point') { + data.element.animate({ + x1: { + begin: seq * delays, + dur: durations, + from: data.x - 10, + to: data.x, + easing: 'easeOutQuart' + }, + x2: { + begin: seq * delays, + dur: durations, + from: data.x - 10, + to: data.x, + easing: 'easeOutQuart' + }, + opacity: { + begin: seq * delays, + dur: durations, + from: 0, + to: 1, + easing: 'easeOutQuart' + } + }); + } else if(data.type === 'grid') { + // Using data.axis we get x or y which we can use to construct our animation definition objects + var pos1Animation = { + begin: seq * delays, + dur: durations, + from: data[data.axis + '1'] - 30, + to: data[data.axis + '1'], + easing: 'easeOutQuart' + }; + + var pos2Animation = { + begin: seq * delays, + dur: durations, + from: data[data.axis + '2'] - 100, + to: data[data.axis + '2'], + easing: 'easeOutQuart' + }; + + var animations = {}; + animations[data.axis + '1'] = pos1Animation; + animations[data.axis + '2'] = pos2Animation; + animations['opacity'] = { + begin: seq * delays, + dur: durations, + from: 0, + to: 1, + easing: 'easeOutQuart' + }; + + data.element.animate(animations); + } +}); + +// For the sake of the example we update the chart every time it's created with a delay of 10 seconds +chart.on('created', function() { + if(window.__exampleAnimateTimeout) { + clearTimeout(window.__exampleAnimateTimeout); + window.__exampleAnimateTimeout = null; + } + window.__exampleAnimateTimeout = setTimeout(chart.update.bind(chart), 12000); +}); + diff --git a/source/site/examples/example-simple-svg-animation.js b/source/site/examples/example-simple-svg-animation.js new file mode 100644 index 00000000..69a57816 --- /dev/null +++ b/source/site/examples/example-simple-svg-animation.js @@ -0,0 +1,63 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], + series: [ + [12, 4, 2, 8, 5, 4, 6, 2, 3, 3, 4, 6], + [4, 8, 9, 3, 7, 2, 10, 5, 8, 1, 7, 10] + ] +}, { + low: 0, + showLine: false, + axisX: { + showLabel: false, + offset: 0 + }, + axisY: { + showLabel: false, + offset: 0 + } +}); + +// Let's put a sequence number aside so we can use it in the event callbacks +var seq = 0; + +// Once the chart is fully created we reset the sequence +chart.on('created', function() { + seq = 0; +}); + +// On each drawn element by Chartist we use the Chartist.Svg API to trigger SMIL animations +chart.on('draw', function(data) { + if(data.type === 'point') { + // If the drawn element is a line we do a simple opacity fade in. This could also be achieved using CSS3 animations. + data.element.animate({ + opacity: { + // The delay when we like to start the animation + begin: seq++ * 80, + // Duration of the animation + dur: 500, + // The value where the animation should start + from: 0, + // The value where it should end + to: 1 + }, + x1: { + begin: seq++ * 80, + dur: 500, + from: data.x - 100, + to: data.x, + // You can specify an easing function name or use easing functions from Chartist.Svg.Easing directly + easing: Chartist.Svg.Easing.easeOutQuart + } + }); + } +}); + +// For the sake of the example we update the chart every time it's created with a delay of 8 seconds +chart.on('created', function() { + if(window.__exampleAnimateTimeout) { + clearTimeout(window.__exampleAnimateTimeout); + window.__exampleAnimateTimeout = null; + } + window.__exampleAnimateTimeout = setTimeout(chart.update.bind(chart), 8000); +}); + From 0341b31ffcbf75c0c0765fff84b94981590d0e65 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 16 Nov 2014 23:13:04 +0100 Subject: [PATCH 080/593] Version 0.4.0 bump and libdist --- bower.json | 2 +- libdist/chartist.js | 894 +++++++++++++++++++++++++-------------- libdist/chartist.min.css | 2 +- libdist/chartist.min.js | 4 +- libdist/chartist.min.map | 2 +- package.json | 2 +- 6 files changed, 591 insertions(+), 315 deletions(-) diff --git a/bower.json b/bower.json index 63408aea..7f139af8 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.3.1", + "version": "0.4.0", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index 9ab8810c..ee7fc6cd 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.3.1 + /* Chartist.js 0.4.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -71,17 +71,34 @@ }; /** - * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified. + * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. * - * @param {String|Number} length - * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel + * @memberof Chartist.Core + * @param {String|Number} value + * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel + */ + Chartist.stripUnit = function(value) { + if(typeof value === 'string') { + value = value.replace(/[^0-9\+-\.]/, ''); + } + + return +value; + }; + + /** + * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {Number} value + * @param {String} unit + * @returns {String} Returns the passed number value with unit. */ - Chartist.getPixelLength = function(length) { - if(typeof length === 'string') { - length = length.replace(/px/i, ''); + Chartist.ensureUnit = function(value, unit) { + if(typeof value === 'number') { + value = value + unit; } - return +length; + return value; }; /** @@ -111,30 +128,21 @@ width = width || '100%'; height = height || '100%'; - // If already contains our svg object we clear it, set width / height and return - if (container.chartistSvg !== undefined) { - svg = container.chartistSvg.attr({ - width: width, - height: height - }).removeAllClasses().addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' - }); - // Clear the draw if its already used before so we start fresh - svg.empty(); + svg = container.querySelector('svg'); + if(svg) { + container.removeChild(svg); + } - } else { - // Create svg object with width and height or use 100% as default - svg = Chartist.Svg('svg').attr({ - width: width, - height: height - }).addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' - }); + // Create svg object with width and height or use 100% as default + svg = new Chartist.Svg('svg').attr({ + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); - // Add the DOM node to our container - container.appendChild(svg._node); - container.chartistSvg = svg; - } + // Add the DOM node to our container + container.appendChild(svg._node); return svg; }; @@ -221,7 +229,7 @@ * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); + return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); }; /** @@ -329,7 +337,7 @@ newMin += bounds.step; } - if (i - bounds.step > bounds.high) { + if (i - bounds.step >= bounds.high) { newMax -= bounds.step; } } @@ -378,8 +386,8 @@ return { x1: options.chartPadding + yOffset, - y1: Math.max((Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max((Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), + y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), y2: options.chartPadding, width: function () { return this.x2 - this.x1; @@ -655,6 +663,81 @@ }; }; + //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas + /** + * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property + * where deltas for specific object properties can be found for the given object nesting level. For nested objects the + * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also + * contain a __delta__ property with the deltas of their level. + * + * @param {Object|Array} a Object that should be used to analyzed delta to object b + * @param {Object|Array} b The second object where the deltas from a should be analyzed + * @returns {Object} Delta descriptor object or null + */ + Chartist.deltaDescriptor = function(a, b) { + var summary = { + added: 0, + removed: 0, + modified: 0 + }; + + function findDeltasRecursively(a, b) { + var descriptor = { + __delta__: {} + }; + + // First check for removed and modified properties + Object.keys(a).forEach(function(property) { + if(!b.hasOwnProperty(property)) { + descriptor.__delta__[property] = { + type: 'remove', + property: property, + ours: a[property] + }; + summary.removed++; + } else { + if(typeof a[property] === 'object') { + var subDescriptor = findDeltasRecursively(a[property], b[property]); + if(subDescriptor) { + descriptor[property] = subDescriptor; + } + } else { + if(a[property] !== b[property]) { + descriptor.__delta__[property] = { + type: 'modify', + property: property, + ours: a[property], + theirs: b[property] + }; + summary.modified++; + } + } + } + }); + + // Check for added properties + Object.keys(b).forEach(function(property) { + if(!a.hasOwnProperty(property)) { + descriptor.__delta__[property] = { + type: 'added', + property: property, + theirs: b[property] + }; + summary.added++; + } + }); + + return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null; + } + + var delta = findDeltasRecursively(a, b); + if(delta) { + delta.__delta__.summary = summary; + } + + return delta; + }; + //http://schepers.cc/getting-to-the-point Chartist.catmullRom2bezier = function (crp, z) { var d = []; @@ -696,7 +779,8 @@ return d; }; - }(window, document, Chartist));;/** + }(window, document, Chartist)); + ;/** * A very basic event module that helps to generate and catch events. * * @module Chartist.Event @@ -757,6 +841,13 @@ handler(data); }); } + + // Emit event to star event handlers + if(handlers['*']) { + handlers['*'].forEach(function(starHandler) { + starHandler(event, data); + }); + } } return { @@ -766,7 +857,8 @@ }; }; - }(window, document, Chartist));;/** + }(window, document, Chartist)); + ;/** * This module provides some basic prototype inheritance utilities. * * @module Chartist.Class @@ -821,7 +913,7 @@ * var banana = new Banana(20, 40); * console.log('banana instanceof Fruit', banana instanceof Fruit); * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); * console.log(banana.sugar); * console.log(banana.eat().sugar); * console.log(banana.color); @@ -889,7 +981,7 @@ * var banana = new Banana(20, 40); * console.log('banana instanceof Fruit', banana instanceof Fruit); * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); * console.log(banana.sugar); * console.log(banana.eat().sugar); * console.log(banana.color); @@ -931,7 +1023,7 @@ * var banana = new Banana(20, 40); * console.log('banana instanceof Fruit', banana instanceof Fruit); * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas\'s prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); * console.log(banana.sugar); * console.log(banana.eat().sugar); * console.log(banana.color); @@ -982,7 +1074,8 @@ cloneDefinitions: cloneDefinitions }; - }(window, document, Chartist));;/** + }(window, document, Chartist)); + ;/** * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. * * @module Chartist.Base @@ -1012,7 +1105,7 @@ * @memberof Chartist.Base */ function detach() { - window.removeEventListener('resize', this.update); + window.removeEventListener('resize', this.resizeListener); this.optionsProvider.removeMediaQueryListeners(); } @@ -1054,8 +1147,21 @@ this.responsiveOptions = responsiveOptions; this.eventEmitter = Chartist.EventEmitter(); this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); + this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); + this.resizeListener = function resizeListener(){ + this.update(); + }.bind(this); + + if(this.container) { + // If chartist was already initialized in this container we are detaching all event listeners first + if(this.container.__chartist__) { + this.container.__chartist__.detach(); + } + + this.container.__chartist__ = this; + } - window.addEventListener('resize', this.update.bind(this)); + window.addEventListener('resize', this.resizeListener); // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. @@ -1086,7 +1192,8 @@ supportsForeignObject: false }); - }(window, document, Chartist));;/** + }(window, document, Chartist)); + ;/** * Chartist SVG module for simple SVG DOM abstraction * * @module Chartist.Svg @@ -1095,6 +1202,10 @@ (function(window, document, Chartist) { 'use strict'; + var svgNs = 'http://www.w3.org/2000/svg', + xmlNs = 'http://www.w3.org/2000/xmlns/', + xhtmlNs = 'http://www.w3.org/1999/xhtml'; + Chartist.xmlNs = { qualifiedName: 'xmlns:ct', prefix: 'ct', @@ -1112,301 +1223,395 @@ * @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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ - Chartist.Svg = function(name, attributes, className, parent, insertFirst) { - - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; + function Svg(name, attributes, className, parent, insertFirst) { + this._node = document.createElementNS(svgNs, name); - /** - * Set attributes on the current SVG element of the wrapper you're currently working on. - * - * @memberof Chartist.Svg - * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {Object} The current wrapper object will be returned so it can be used for chaining. - */ - function attr(node, attributes, ns) { - Object.keys(attributes).forEach(function(key) { - // If the attribute value is undefined we can skip this one - if(attributes[key] === undefined) { - return; - } - - if(ns) { - node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); - } else { - node.setAttribute(key, attributes[key]); - } - }); + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + } - return node; + if(attributes) { + this.attr(attributes); } - /** - * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. - * - * @memberof Chartist.Svg - * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @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 - * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data - */ - function elem(name, attributes, className, parentNode, insertFirst) { - var node = document.createElementNS(svgNs, name); + if(className) { + this.addClass(className); + } - // If this is an SVG element created then custom namespace - if(name === 'svg') { - node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); } - if(parentNode) { - if(insertFirst && parentNode.firstChild) { - parentNode.insertBefore(node, parentNode.firstChild); - } else { - parentNode.appendChild(node); - } - } + this._parent = parent; + } + } - if(attributes) { - attr(node, attributes); + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Chartist.Svg + * @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. + * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @returns {Object} The current wrapper object will be returned so it can be used for chaining. + */ + function attr(attributes, ns) { + Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; } - if(className) { - addClass(node, className); + if(ns) { + this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + } else { + this._node.setAttribute(key, attributes[key]); } + }.bind(this)); + + return this; + } + + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + function elem(name, attributes, className, insertFirst) { + return new Chartist.Svg(name, attributes, className, this, insertFirst); + } - return node; + /** + * 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. + * + * @memberof Chartist.Svg + * @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 + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @returns {Object} New wrapper object that wraps the foreignObject element + */ + function foreignObject(content, attributes, className, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; } - /** - * 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. - * - * @memberof Chartist.Svg - * @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 - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Object} New wrapper object that wraps the foreignObject element - */ - function foreignObject(content, attributes, className, parent, insertFirst) { - // If content is string then we convert it to DOM - // TODO: Handle case where content is not a string nor a DOM Node - if(typeof content === 'string') { - var container = document.createElement('div'); - container.innerHTML = content; - content = container.firstChild; - } + // Adding namespace to content element + content.setAttribute('xmlns', xhtmlNs); - // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = this.elem('foreignObject', attributes, className, insertFirst); - // Creating the foreignObject without required extension attribute (as described here - // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = parent.elem('foreignObject', attributes, className, insertFirst); + // Add content to foreignObjectElement + fnObj._node.appendChild(content); - // Add content to foreignObjectElement - fnObj._node.appendChild(content); + return fnObj; + } - return fnObj; - } + /** + * This method adds a new text element to the current Chartist.Svg wrapper. + * + * @memberof Chartist.Svg + * @param {String} t The text that should be added to the text element that is created + * @returns {Object} The same wrapper object that was used to add the newly created element + */ + function text(t) { + this._node.appendChild(document.createTextNode(t)); + return this; + } - /** - * This method adds a new text element to the current Chartist.Svg wrapper. - * - * @memberof Chartist.Svg - * @param {String} t The text that should be added to the text element that is created - * @returns {Object} The same wrapper object that was used to add the newly created element - */ - function text(node, t) { - node.appendChild(document.createTextNode(t)); + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Chartist.Svg + * @returns {Object} The same wrapper object that got emptied + */ + function empty() { + while (this._node.firstChild) { + this._node.removeChild(this._node.firstChild); } - /** - * This method will clear all child nodes of the current wrapper object. - * - * @memberof Chartist.Svg - * @returns {Object} The same wrapper object that got emptied - */ - function empty(node) { - while (node.firstChild) { - node.removeChild(node.firstChild); - } - } + return this; + } - /** - * 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. - * - * @memberof Chartist.Svg - * @returns {Object} The parent wrapper object of the element that got removed - */ - function remove(node) { - node.parentNode.removeChild(node); - } + /** + * 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. + * + * @memberof Chartist.Svg + * @returns {Object} The parent wrapper object of the element that got removed + */ + function remove() { + this._node.parentNode.removeChild(this._node); + return this._parent; + } - /** - * This method will replace the element with a new element that can be created outside of the current DOM. - * - * @memberof Chartist.Svg - * @param {Object} newElement The new wrapper object that will be used to replace the current wrapper object - * @returns {Object} The wrapper of the new element - */ - function replace(node, newChild) { - node.parentNode.replaceChild(newChild, node); - } + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Chartist.Svg + * @param {Object} newElement The new Chartist.Svg object that will be used to replace the current wrapper object + * @returns {Object} The wrapper of the new element + */ + function replace(newElement) { + this._node.parentNode.replaceChild(newElement._node, this._node); + newElement._parent = this._parent; + this._parent = null; + return newElement; + } - /** - * This method will append an element to the current element as a child. - * - * @memberof Chartist.Svg - * @param {Object} element The element that should be added as a child - * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Object} The wrapper of the appended object - */ - function append(node, child, insertFirst) { - if(insertFirst && node.firstChild) { - node.insertBefore(child, node.firstChild); - } else { - node.appendChild(child); - } + /** + * This method will append an element to the current element as a child. + * + * @memberof Chartist.Svg + * @param {Object} element The Chartist.Svg element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @returns {Object} The wrapper of the appended object + */ + function append(element, insertFirst) { + if(insertFirst && this._node.firstChild) { + this._node.insertBefore(element._node, this._node.firstChild); + } else { + this._node.appendChild(element._node); } - /** - * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. - * - * @memberof Chartist.Svg - * @returns {Array} A list of classes or an empty array if there are no classes on the current element - */ - function classes(node) { - return node.getAttribute('class') ? node.getAttribute('class').trim().split(/\s+/) : []; - } + return this; + } - /** - * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element - */ - function addClass(node, names) { - node.setAttribute('class', - classes(node) - .concat(names.trim().split(/\s+/)) - .filter(function(elem, pos, self) { - return self.indexOf(elem) === pos; - }).join(' ') - ); - } + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Chartist.Svg + * @returns {Array} A list of classes or an empty array if there are no classes on the current element + */ + function classes() { + return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; + } - /** - * Removes one or a space separated list of classes from the current element. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element - */ - function removeClass(node, names) { - var removedClasses = names.trim().split(/\s+/); + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ + function addClass(names) { + this._node.setAttribute('class', + this.classes(this._node) + .concat(names.trim().split(/\s+/)) + .filter(function(elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ') + ); + + return this; + } - node.setAttribute('class', classes(node).filter(function(name) { - return removedClasses.indexOf(name) === -1; - }).join(' ')); - } + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Object} The wrapper of the current element + */ + function removeClass(names) { + var removedClasses = names.trim().split(/\s+/); - /** - * Removes all classes from the current element. - * - * @memberof Chartist.Svg - * @returns {Object} The wrapper of the current element - */ - function removeAllClasses(node) { - node.setAttribute('class', ''); - } + this._node.setAttribute('class', this.classes(this._node).filter(function(name) { + return removedClasses.indexOf(name) === -1; + }).join(' ')); - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Svg - * @return {Number} The elements height in pixels - */ - function height(node) { - return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight; - } + return this; + } - /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @return {Number} The elements width in pixels - */ - function width(node) { - return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth; + /** + * Removes all classes from the current element. + * + * @memberof Chartist.Svg + * @returns {Object} The wrapper of the current element + */ + function removeAllClasses() { + this._node.setAttribute('class', ''); + } + + /** + * Get element height with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Svg + * @return {Number} The elements height in pixels + */ + function height() { + return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; + } + + /** + * Get element width with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + function width() { + return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + } + + /** + * 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 values specifying a cubic Bézier curve. + * **An animations object could look like this:** + * ```javascript + * element.animate({ + * opacity: { + * dur: 1000, + * from: 0, + * to: 1 + * }, + * x1: { + * dur: '1000ms', + * from: 100, + * to: 200, + * easing: 'easeOutQuart' + * }, + * y1: { + * dur: '2s', + * from: 0, + * to: 100 + * } + * }); + * ``` + * **Automatic unit conversion** + * 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. + * **Guided mode** + * 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. 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. + * If guided mode is enabled the following behavior is added: + * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - The animate element will be forced to use `fill="freeze"` + * - After the animation the element attribute value will be set to the `to` value of the animation + * - The animate element is deleted from the DOM + * + * @memberof Chartist.Svg + * @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. + * @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. + * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. + * @returns {Object} The current element where the animation was added + */ + function animate(animations, guided, eventEmitter) { + if(guided === undefined) { + guided = true; } - return { - _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst), - _parent: parent, - parent: function() { - return this._parent; - }, - attr: function(attributes, ns) { - attr(this._node, attributes, ns); - return this; - }, - empty: function() { - empty(this._node); - return this; - }, - remove: function() { - remove(this._node); - return this.parent(); - }, - replace: function(newElement) { - newElement._parent = this._parent; - replace(this._node, newElement._node); - return newElement; - }, - append: function(element, insertFirst) { - element._parent = this; - append(this._node, element._node, insertFirst); - return element; - }, - elem: function(name, attributes, className, insertFirst) { - return Chartist.Svg(name, attributes, className, this, insertFirst); - }, - foreignObject: function(content, attributes, className, insertFirst) { - return foreignObject(content, attributes, className, this, insertFirst); - }, - text: function(t) { - text(this._node, t); - return this; - }, - addClass: function(names) { - addClass(this._node, names); - return this; - }, - removeClass: function(names) { - removeClass(this._node, names); - return this; - }, - removeAllClasses: function() { - removeAllClasses(this._node); - return this; - }, - classes: function() { - return classes(this._node); - }, - height: function() { - return height(this._node); - }, - width: function() { - return width(this._node); + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + + function createAnimate(animationDefinition, guided) { + var attributeProperties = {}, + animate, + easing; + + // Check if an easing is specified in the definition object and delete it from the object as it will not + // be part of the animate element attributes. + if(animationDefinition.easing) { + // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object + easing = animationDefinition.easing instanceof Array ? + animationDefinition.easing : + Chartist.Svg.Easing[animationDefinition.easing]; + delete animationDefinition.easing; + } + + // Adding "fill: freeze" if we are in guided mode and set initial attribute values + if(guided) { + animationDefinition.fill = 'freeze'; + // Animated property on our element should already be set to the animation from value in guided mode + attributeProperties[attribute] = animationDefinition.from; + this.attr(attributeProperties); + } + + if(easing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = easing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); + + animate = this.elem('animate', Chartist.extend({ + attributeName: attribute + }, animationDefinition)); + + if(eventEmitter) { + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animationDefinition + }); + }.bind(this)); + } + + animate._node.addEventListener('endEvent', function handleEndEvent() { + if(eventEmitter) { + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animationDefinition + }); + } + + if(guided) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this)); + } + + // If current attribute is an array of definition objects we create an animate for each and disable guided mode + if(animations[attribute] instanceof Array) { + animations[attribute].forEach(function(animationDefinition) { + createAnimate.bind(this)(animationDefinition, false); + }.bind(this)); + } else { + createAnimate.bind(this)(animations[attribute], guided); } - }; - }; + + }.bind(this)); + + return this; + } + + Chartist.Svg = Chartist.Class.extend({ + constructor: Svg, + attr: attr, + elem: elem, + foreignObject: foreignObject, + text: text, + empty: empty, + remove: remove, + replace: replace, + append: append, + classes: classes, + addClass: addClass, + removeClass: removeClass, + removeAllClasses: removeAllClasses, + height: height, + width: width, + animate: animate + }); /** * 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. @@ -1419,7 +1624,42 @@ return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); }; - }(window, document, Chartist));;/** + /** + * 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. + * + * @memberof Chartist.Svg + */ + var easingCubicBeziers = { + easeInSine: [0.47, 0, 0.745, 0.715], + easeOutSine: [0.39, 0.575, 0.565, 1], + easeInOutSine: [0.445, 0.05, 0.55, 0.95], + easeInQuad: [0.55, 0.085, 0.68, 0.53], + easeOutQuad: [0.25, 0.46, 0.45, 0.94], + easeInOutQuad: [0.455, 0.03, 0.515, 0.955], + easeInCubic: [0.55, 0.055, 0.675, 0.19], + easeOutCubic: [0.215, 0.61, 0.355, 1], + easeInOutCubic: [0.645, 0.045, 0.355, 1], + easeInQuart: [0.895, 0.03, 0.685, 0.22], + easeOutQuart: [0.165, 0.84, 0.44, 1], + easeInOutQuart: [0.77, 0, 0.175, 1], + easeInQuint: [0.755, 0.05, 0.855, 0.06], + easeOutQuint: [0.23, 1, 0.32, 1], + easeInOutQuint: [0.86, 0, 0.07, 1], + easeInExpo: [0.95, 0.05, 0.795, 0.035], + easeOutExpo: [0.19, 1, 0.22, 1], + easeInOutExpo: [1, 0, 0, 1], + easeInCirc: [0.6, 0.04, 0.98, 0.335], + easeOutCirc: [0.075, 0.82, 0.165, 1], + easeInOutCirc: [0.785, 0.135, 0.15, 0.86], + easeInBack: [0.6, -0.28, 0.735, 0.045], + easeOutBack: [0.175, 0.885, 0.32, 1.275], + easeInOutBack: [0.68, -0.55, 0.265, 1.55] + }; + + Chartist.Svg.Easing = easingCubicBeziers; + + }(window, document, Chartist)); + ;/** * 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. * * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. @@ -1450,7 +1690,7 @@ showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 30 + scaleMinSpace: 20 }, width: undefined, height: undefined, @@ -1565,7 +1805,7 @@ if(options.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.high), bounds.low); + var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); // If we need to draw area shapes we just make a copy of our pathElements SVG path array var areaPathElements = pathElements.slice(); @@ -1578,22 +1818,45 @@ areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); // Create the new path for the area shape with the area class from the options - seriesGroups[i].elem('path', { + var area = seriesGroups[i].elem('path', { d: areaPathElements.join('') }, options.classNames.area, true).attr({ 'values': normalizedData[i] }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: area + }); } if(options.showLine) { - seriesGroups[i].elem('path', { + var line = seriesGroups[i].elem('path', { d: pathElements.join('') }, options.classNames.line, true).attr({ 'values': normalizedData[i] }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: line + }); } } } + + this.eventEmitter.emit('created', { + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options + }); } /** @@ -1778,7 +2041,7 @@ showLabel: true, showGrid: true, labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 30 + scaleMinSpace: 20 }, width: undefined, height: undefined, @@ -1871,6 +2134,13 @@ }); } } + + this.eventEmitter.emit('created', { + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options + }); } /** @@ -2173,6 +2443,12 @@ // (except for last slice) startAngle = endAngle; } + + this.eventEmitter.emit('created', { + chartRect: chartRect, + svg: this.svg, + options: options + }); } /** diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index dd341785..b19d6893 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.3.1 +/* Chartist.js 0.4.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 0167b46f..2c4c9b55 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.3.1 +/* Chartist.js 0.4.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.3.1",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.getPixelLength=function(a){return"string"==typeof a&&(a=a.replace(/px/i,"")),+a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",void 0!==a.chartistSvg?(f=a.chartistSvg.attr({width:b,height:d}).removeAllClasses().addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),f.empty()):(f=c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),a.chartistSvg=f),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.getPixelLength(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.stepi.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.getPixelLength(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.getPixelLength(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;jd;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.3.1",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;j0?e:null}var d={added:0,removed:0,modified:0},e=c(a,b);return e&&(e.__delta__.summary=d),e},c.catmullRom2bezier=function(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 6fce0ca2..098ef2c8 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","getPixelLength","length","replace","querySelector","query","Node","createSvg","container","width","height","className","svg","undefined","chartistSvg","attr","removeAllClasses","addClass","style","empty","Svg","appendChild","_node","getDataArray","data","array","i","series","j","normalizeDataArray","dataArray","orderOfMagnitude","value","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18727,"pos":18722,"col":16,"line":485,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18727,"pos":18722,"col":16,"line":485,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","on","off","Base","isSupported","addEventListener","bind","setTimeout","xmlNs","qualifiedName","prefix","uri","name","insertFirst","node","ns","keys","key","setAttributeNS","setAttribute","parentNode","createElementNS","svgNs","firstChild","insertBefore","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","removeChild","remove","newChild","replaceChild","append","child","classes","getAttribute","trim","split","names","filter","self","removeClass","removedClasses","clientHeight","getBBox","clientWidth","_parent","newElement","feature","implementation","hasFeature","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.3.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.3.1';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit px if present. If a number is passed then this will be returned unmodified.\n *\n * @param {String|Number} length\n * @returns {Number} Returns the pixel as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.getPixelLength = function(length) {\n if(typeof length === 'string') {\n length = length.replace(/px/i, '');\n }\n\n return +length;\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 * 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 // If already contains our svg object we clear it, set width / height and return\n if (container.chartistSvg !== undefined) {\n svg = container.chartistSvg.attr({\n width: width,\n height: height\n }).removeAllClasses().addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n // Clear the draw if its already used before so we start fresh\n svg.empty();\n\n } else {\n // Create svg object with width and height or use 100% as default\n svg = 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 container.chartistSvg = svg;\n }\n\n return svg;\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.getPixelLength(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step > bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.getPixelLength(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.getPixelLength(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\n\n }(window, document, Chartist));;/**\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\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n }(window, document, Chartist));;/**\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 * @returns {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\\'s 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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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\\'s 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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\\'s 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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\n cloneDefinitions: cloneDefinitions\n };\n\n }(window, document, Chartist));;/**\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.update);\n this.optionsProvider.removeMediaQueryListeners();\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 }\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 }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\n this.options = options;\n this.responsiveOptions = responsiveOptions;\n this.eventEmitter = Chartist.EventEmitter();\n this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility');\n\n window.addEventListener('resize', this.update.bind(this));\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 * 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 Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n Chartist.Svg = function(name, attributes, className, parent, insertFirst) {\n\n var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(node, attributes, ns) {\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(ns) {\n node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]);\n } else {\n node.setAttribute(key, attributes[key]);\n }\n });\n\n return node;\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, parentNode, insertFirst) {\n var node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\n }\n\n if(parentNode) {\n if(insertFirst && parentNode.firstChild) {\n parentNode.insertBefore(node, parentNode.firstChild);\n } else {\n parentNode.appendChild(node);\n }\n }\n\n if(attributes) {\n attr(node, attributes);\n }\n\n if(className) {\n addClass(node, className);\n }\n\n return 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 * @returns {Object} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, attributes, className, parent, 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', xhtmlNs);\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 = parent.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 * @returns {Object} The same wrapper object that was used to add the newly created element\n */\n function text(node, t) {\n node.appendChild(document.createTextNode(t));\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The same wrapper object that got emptied\n */\n function empty(node) {\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\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 * @returns {Object} The parent wrapper object of the element that got removed\n */\n function remove(node) {\n node.parentNode.removeChild(node);\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 {Object} newElement The new wrapper object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(node, newChild) {\n node.parentNode.replaceChild(newChild, node);\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Object} element The element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @returns {Object} The wrapper of the appended object\n */\n function append(node, child, insertFirst) {\n if(insertFirst && node.firstChild) {\n node.insertBefore(child, node.firstChild);\n } else {\n node.appendChild(child);\n }\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 * @returns {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes(node) {\n return node.getAttribute('class') ? 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 * @returns {Object} The wrapper of the current element\n */\n function addClass(node, names) {\n node.setAttribute('class',\n classes(node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\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 * @returns {Object} The wrapper of the current element\n */\n function removeClass(node, names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n node.setAttribute('class', classes(node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses(node) {\n node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height(node) {\n return node.clientHeight || Math.round(node.getBBox().height) || node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width(node) {\n return node.clientWidth || Math.round(node.getBBox().width) || node.parentNode.clientWidth;\n }\n\n return {\n _node: elem(name, attributes, className, parent ? parent._node : undefined, insertFirst),\n _parent: parent,\n parent: function() {\n return this._parent;\n },\n attr: function(attributes, ns) {\n attr(this._node, attributes, ns);\n return this;\n },\n empty: function() {\n empty(this._node);\n return this;\n },\n remove: function() {\n remove(this._node);\n return this.parent();\n },\n replace: function(newElement) {\n newElement._parent = this._parent;\n replace(this._node, newElement._node);\n return newElement;\n },\n append: function(element, insertFirst) {\n element._parent = this;\n append(this._node, element._node, insertFirst);\n return element;\n },\n elem: function(name, attributes, className, insertFirst) {\n return Chartist.Svg(name, attributes, className, this, insertFirst);\n },\n foreignObject: function(content, attributes, className, insertFirst) {\n return foreignObject(content, attributes, className, this, insertFirst);\n },\n text: function(t) {\n text(this._node, t);\n return this;\n },\n addClass: function(names) {\n addClass(this._node, names);\n return this;\n },\n removeClass: function(names) {\n removeClass(this._node, names);\n return this;\n },\n removeAllClasses: function() {\n removeAllClasses(this._node);\n return this;\n },\n classes: function() {\n return classes(this._node);\n },\n height: function() {\n return height(this._node);\n },\n width: function() {\n return width(this._node);\n }\n };\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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1');\n };\n\n }(window, document, Chartist));;/**\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g');\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.high), bounds.low);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n\n if(options.showLine) {\n seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n }\n }\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 30\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18760,"pos":18755,"col":16,"line":493,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18760,"pos":18755,"col":16,"line":493,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","deltaDescriptor","a","b","findDeltasRecursively","descriptor","__delta__","Object","keys","property","hasOwnProperty","subDescriptor","ours","theirs","summary","modified","removed","added","delta","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","name","insertFirst","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","_parent","ns","key","prefix","setAttribute","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","parentNode","newElement","replaceChild","append","classes","getAttribute","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","easing","attributeProperties","Easing","fill","from","calcMode","keySplines","keyTimes","begin","dur","attributeName","params","to","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","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.4.0\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.3.1';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas\n /**\n * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property\n * where deltas for specific object properties can be found for the given object nesting level. For nested objects the\n * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also\n * contain a __delta__ property with the deltas of their level.\n *\n * @param {Object|Array} a Object that should be used to analyzed delta to object b\n * @param {Object|Array} b The second object where the deltas from a should be analyzed\n * @returns {Object} Delta descriptor object or null\n */\n Chartist.deltaDescriptor = function(a, b) {\n var summary = {\n added: 0,\n removed: 0,\n modified: 0\n };\n\n function findDeltasRecursively(a, b) {\n var descriptor = {\n __delta__: {}\n };\n\n // First check for removed and modified properties\n Object.keys(a).forEach(function(property) {\n if(!b.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'remove',\n property: property,\n ours: a[property]\n };\n summary.removed++;\n } else {\n if(typeof a[property] === 'object') {\n var subDescriptor = findDeltasRecursively(a[property], b[property]);\n if(subDescriptor) {\n descriptor[property] = subDescriptor;\n }\n } else {\n if(a[property] !== b[property]) {\n descriptor.__delta__[property] = {\n type: 'modify',\n property: property,\n ours: a[property],\n theirs: b[property]\n };\n summary.modified++;\n }\n }\n }\n });\n\n // Check for added properties\n Object.keys(b).forEach(function(property) {\n if(!a.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'added',\n property: property,\n theirs: b[property]\n };\n summary.added++;\n }\n });\n\n return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null;\n }\n\n var delta = findDeltasRecursively(a, b);\n if(delta) {\n delta.__delta__.summary = summary;\n }\n\n return delta;\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 }\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 }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function Svg(name, attributes, className, parent, insertFirst) {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 this._parent = parent;\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(attributes, ns) {\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {Object} 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 * 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 * @returns {Object} 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', xhtmlNs);\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 * @returns {Object} 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 * @returns {Object} 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 * @returns {Object} 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 {Object} newElement The new Chartist.Svg object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(newElement) {\n this._node.parentNode.replaceChild(newElement._node, this._node);\n newElement._parent = this._parent;\n this._parent = null;\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 {Object} 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 * @returns {Object} 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 * @returns {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 * @returns {Object} 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 * @returns {Object} 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 * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses() {\n this._node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 values 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. 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 * - The animate element will be forced to use `fill=\"freeze\"`\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 * @returns {Object} 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 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 // 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\n if(easing) {\n animationDefinition.calcMode = 'spline';\n animationDefinition.keySplines = easing.join(' ');\n animationDefinition.keyTimes = '0;1';\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 animate = this.elem('animate', Chartist.extend({\n attributeName: attribute\n }, animationDefinition));\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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 }(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g');\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index e6307bff..9d3a3f7e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.3.1", + "version": "0.4.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From ad594f80285cf55ba101cb012d8cbea3cae42a32 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 17 Nov 2014 14:13:10 +0100 Subject: [PATCH 081/593] Added this as return value so calls to chart can be chained up easily --- source/scripts/chartist.base.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js index 4b7c5da7..89a6856f 100644 --- a/source/scripts/chartist.base.js +++ b/source/scripts/chartist.base.js @@ -20,6 +20,7 @@ */ function update() { this.createChart(this.optionsProvider.currentOptions); + return this; } /** @@ -30,6 +31,7 @@ function detach() { window.removeEventListener('resize', this.resizeListener); this.optionsProvider.removeMediaQueryListeners(); + return this; } /** @@ -41,6 +43,7 @@ */ function on(event, handler) { this.eventEmitter.addEventHandler(event, handler); + return this; } /** @@ -52,6 +55,7 @@ */ function off(event, handler) { this.eventEmitter.removeEventHandler(event, handler); + return this; } /** From db5046627cbdc5e29c4dbaa171d16df9b943688c Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 17 Nov 2014 14:21:16 +0100 Subject: [PATCH 082/593] Added classes to the label and grid gorups --- source/scripts/chartist.bar.js | 8 ++++++-- source/scripts/chartist.line.js | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js index d2848696..04525a06 100644 --- a/source/scripts/chartist.bar.js +++ b/source/scripts/chartist.bar.js @@ -38,9 +38,11 @@ classNames: { chart: 'ct-chart-bar', label: 'ct-label', + labelGroup: 'ct-labels', series: 'ct-series', bar: 'ct-bar', grid: 'ct-grid', + gridGroup: 'ct-grids', vertical: 'ct-vertical', horizontal: 'ct-horizontal' } @@ -59,8 +61,8 @@ var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing - var labels = this.svg.elem('g'), - grid = this.svg.elem('g'), + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup), // Projected 0 point zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); @@ -192,9 +194,11 @@ * classNames: { * chart: 'ct-chart-bar', * label: 'ct-label', + * labelGroup: 'ct-labels', * series: 'ct-series', * bar: 'ct-bar', * grid: 'ct-grid', + * gridGroup: 'ct-grids', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' * } diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js index 8a0a994a..aea42aa6 100644 --- a/source/scripts/chartist.line.js +++ b/source/scripts/chartist.line.js @@ -44,11 +44,13 @@ 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', vertical: 'ct-vertical', horizontal: 'ct-horizontal' } @@ -67,8 +69,8 @@ var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing - var labels = this.svg.elem('g'), - grid = this.svg.elem('g'); + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup); Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); @@ -269,11 +271,13 @@ * 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', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' * } From 193a8c46d79a5d33103bd1509b3ca68365ddd662 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 20 Nov 2014 23:13:44 +0100 Subject: [PATCH 083/593] Fixed bug in strip unit --- source/scripts/chartist.core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js index 07677910..7d2032be 100644 --- a/source/scripts/chartist.core.js +++ b/source/scripts/chartist.core.js @@ -62,7 +62,7 @@ Chartist.version = '0.3.1'; */ Chartist.stripUnit = function(value) { if(typeof value === 'string') { - value = value.replace(/[^0-9\+-\.]/, ''); + value = value.replace(/[^0-9\+-\.]/g, ''); } return +value; From cd57f414348076b1bebb97d623aced35337ce85e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Nov 2014 00:19:37 +0100 Subject: [PATCH 084/593] Added more functionality to Chartist.Svg: select child elements, parent, root as well as a Svg list wrapper with delegation functions --- source/scripts/chartist.svg.js | 214 +++++++++++++++++++++++++-------- 1 file changed, 165 insertions(+), 49 deletions(-) diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js index 969f46a7..2e598af5 100644 --- a/source/scripts/chartist.svg.js +++ b/source/scripts/chartist.svg.js @@ -21,37 +21,40 @@ * 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. * * @memberof Chartist.Svg - * @param {String} name The name of the SVG element to create + * @constructor + * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg * @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. * @param {String} className This class or class list will be added to the SVG element * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child * @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 - * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ function Svg(name, attributes, className, parent, insertFirst) { - this._node = document.createElementNS(svgNs, name); - - // If this is an SVG element created then custom namespace - if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); - } + // If Svg is getting called with an SVG element we just return the wrapper + if(name instanceof SVGElement) { + this._node = name; + } else { + this._node = document.createElementNS(svgNs, name); - if(attributes) { - this.attr(attributes); - } + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + } - if(className) { - this.addClass(className); - } + if(attributes) { + this.attr(attributes); + } - if(parent) { - if (insertFirst && parent._node.firstChild) { - parent._node.insertBefore(this._node, parent._node.firstChild); - } else { - parent._node.appendChild(this._node); + if(className) { + this.addClass(className); } - this._parent = parent; + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); + } + } } } @@ -59,11 +62,19 @@ * Set attributes on the current SVG element of the wrapper you're currently working on. * * @memberof Chartist.Svg - * @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. + * @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. * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {Object} The current wrapper object will be returned so it can be used for chaining. + * @returns {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. */ function attr(attributes, ns) { + if(typeof attributes === 'string') { + if(ns) { + return this._node.getAttributeNS(ns, attributes); + } else { + return this._node.getAttribute(attributes); + } + } + Object.keys(attributes).forEach(function(key) { // If the attribute value is undefined we can skip this one if(attributes[key] === undefined) { @@ -88,12 +99,56 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @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 - * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ function elem(name, attributes, className, insertFirst) { return new Chartist.Svg(name, attributes, className, this, insertFirst); } + /** + * Returns the parent Chartist.SVG wrapper object + * + * @returns {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. + */ + function parent() { + return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; + } + + /** + * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. + * + * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element + */ + function root() { + var node = this._node; + while(node.nodeName !== 'svg') { + node = node.parentNode; + } + return new Chartist.Svg(node); + } + + /** + * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found + */ + function querySelector(selector) { + var foundNode = this._node.querySelector(selector); + return foundNode ? new Chartist.Svg(foundNode) : null; + } + + /** + * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found + */ + function querySelectorAll(selector) { + var foundNodes = this._node.querySelectorAll(selector); + return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; + } + /** * 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. * @@ -102,7 +157,7 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Object} New wrapper object that wraps the foreignObject element + * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element */ function foreignObject(content, attributes, className, insertFirst) { // If content is string then we convert it to DOM @@ -131,7 +186,7 @@ * * @memberof Chartist.Svg * @param {String} t The text that should be added to the text element that is created - * @returns {Object} The same wrapper object that was used to add the newly created element + * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element */ function text(t) { this._node.appendChild(document.createTextNode(t)); @@ -142,7 +197,7 @@ * This method will clear all child nodes of the current wrapper object. * * @memberof Chartist.Svg - * @returns {Object} The same wrapper object that got emptied + * @returns {Chartist.Svg} The same wrapper object that got emptied */ function empty() { while (this._node.firstChild) { @@ -156,24 +211,22 @@ * 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. * * @memberof Chartist.Svg - * @returns {Object} The parent wrapper object of the element that got removed + * @returns {Chartist.Svg} The parent wrapper object of the element that got removed */ function remove() { this._node.parentNode.removeChild(this._node); - return this._parent; + return new Chartist.Svg(this._node.parentNode); } /** * This method will replace the element with a new element that can be created outside of the current DOM. * * @memberof Chartist.Svg - * @param {Object} newElement The new Chartist.Svg object that will be used to replace the current wrapper object - * @returns {Object} The wrapper of the new element + * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object + * @returns {Chartist.Svg} The wrapper of the new element */ function replace(newElement) { this._node.parentNode.replaceChild(newElement._node, this._node); - newElement._parent = this._parent; - this._parent = null; return newElement; } @@ -181,9 +234,9 @@ * This method will append an element to the current element as a child. * * @memberof Chartist.Svg - * @param {Object} element The Chartist.Svg element that should be added as a child + * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Object} The wrapper of the appended object + * @returns {Chartist.Svg} The wrapper of the appended object */ function append(element, insertFirst) { if(insertFirst && this._node.firstChild) { @@ -210,7 +263,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element + * @returns {Chartist.Svg} The wrapper of the current element */ function addClass(names) { this._node.setAttribute('class', @@ -229,7 +282,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element + * @returns {Chartist.Svg} The wrapper of the current element */ function removeClass(names) { var removedClasses = names.trim().split(/\s+/); @@ -245,10 +298,12 @@ * Removes all classes from the current element. * * @memberof Chartist.Svg - * @returns {Object} The wrapper of the current element + * @returns {Chartist.Svg} The wrapper of the current element */ function removeAllClasses() { this._node.setAttribute('class', ''); + + return this; } /** @@ -274,7 +329,7 @@ } /** - * 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 values specifying a cubic Bézier curve. + * 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. * **An animations object could look like this:** * ```javascript * element.animate({ @@ -299,10 +354,12 @@ * **Automatic unit conversion** * 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. * **Guided mode** - * 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. 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. + * 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. * If guided mode is enabled the following behavior is added: * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) * - The animate element will be forced to use `fill="freeze"` + * - 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. * - After the animation the element attribute value will be set to the `to` value of the animation * - The animate element is deleted from the DOM * @@ -310,7 +367,7 @@ * @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. * @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. * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. - * @returns {Object} The current element where the animation was added + * @returns {Chartist.Svg} The current element where the animation was added */ function animate(animations, guided, eventEmitter) { if(guided === undefined) { @@ -322,6 +379,7 @@ function createAnimate(animationDefinition, guided) { var attributeProperties = {}, animate, + timeout, easing; // Check if an easing is specified in the definition object and delete it from the object as it will not @@ -334,28 +392,40 @@ delete animationDefinition.easing; } + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); + + if(easing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = easing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + // Adding "fill: freeze" if we are in guided mode and set initial attribute values if(guided) { animationDefinition.fill = 'freeze'; // Animated property on our element should already be set to the animation from value in guided mode attributeProperties[attribute] = animationDefinition.from; this.attr(attributeProperties); - } - if(easing) { - animationDefinition.calcMode = 'spline'; - animationDefinition.keySplines = easing.join(' '); - animationDefinition.keyTimes = '0;1'; + // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin + // which needs to be in ms aside + timeout = Chartist.stripUnit(animationDefinition.begin || 0); + animationDefinition.begin = 'indefinite'; } - // If numeric dur or begin was provided we assume milli seconds - animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); - animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); - animate = this.elem('animate', Chartist.extend({ attributeName: attribute }, animationDefinition)); + if(guided) { + // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout + setTimeout(function() { + animate._node.beginElement(); + }, timeout); + } + if(eventEmitter) { animate._node.addEventListener('beginEvent', function handleBeginEvent() { eventEmitter.emit('animationBegin', { @@ -403,6 +473,10 @@ constructor: Svg, attr: attr, elem: elem, + parent: parent, + root: root, + querySelector: querySelector, + querySelectorAll: querySelectorAll, foreignObject: foreignObject, text: text, empty: empty, @@ -463,4 +537,46 @@ Chartist.Svg.Easing = easingCubicBeziers; + /** + * 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. + * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. + * + * @memberof Chartist.Svg + * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) + * @constructor + */ + function SvgList(nodeList) { + var list = this; + + this.svgElements = []; + for(var i = 0; i < nodeList.length; i++) { + this.svgElements.push(new Chartist.Svg(nodeList[i])); + } + + // Add delegation methods for Chartist.Svg + Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { + return ['constructor', + 'parent', + 'querySelector', + 'querySelectorAll', + 'replace', + 'append', + 'classes', + 'height', + 'width'].indexOf(prototypeProperty) === -1; + }).forEach(function(prototypeProperty) { + list[prototypeProperty] = function() { + var args = Array.prototype.slice.call(arguments, 0); + list.svgElements.forEach(function(element) { + Chartist.Svg.prototype[prototypeProperty].apply(element, args); + }); + return list; + }; + }); + } + + Chartist.Svg.List = Chartist.Class.extend({ + constructor: SvgList + }); + }(window, document, Chartist)); From 9f36508b4d0ce049849af22aea3aa5fbc49d15c4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Nov 2014 00:44:10 +0100 Subject: [PATCH 085/593] Added projects / wrapper libraries table to index page --- source/site/data/pages/index.yml | 31 +++++++++++++++++++++++++++++++ source/site/partials/table.hbs | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/source/site/data/pages/index.yml b/source/site/data/pages/index.yml index d9d9e0df..fedce55c 100644 --- a/source/site/data/pages/index.yml +++ b/source/site/data/pages/index.yml @@ -202,6 +202,37 @@ sections: - name: iOS Safari 7 status: supported text: Supported + + - title: Projects / Wrapper libraries + level: 4 + items: + - type: text + data: + text: These projects and wrapper libraries are known to me right now that either use Chartist.js or wrap them into a library for usage in a framework. If you know other projects that use Chartist.js please let us know or make a pull request for this file. + - type: table + data: + id: chartist-projects-table + header: + - Project + - Type + - Website + rows: + - + - ng-chartist.js + - Angular Directive + - 'https://github.com/paradox41/ng-chartist.js' + - + - react-chartist + - React Component + - 'https://fraserxu.me/react-chartist' + - + - meteor-chartist-js + - Meteor Package + - 'https://github.com/mfpierre/meteor-chartist-js' + - + - tablepress_chartist + - Wordpress / Tablepress Extension + - 'https://github.com/soderlind/tablepress_chartist' - title: Chart CSS animation example level: 3 items: diff --git a/source/site/partials/table.hbs b/source/site/partials/table.hbs index 51ee59e0..74cdf277 100644 --- a/source/site/partials/table.hbs +++ b/source/site/partials/table.hbs @@ -14,7 +14,7 @@ {{#each rows}} {{#each this}} - {{this}} + {{{this}}} {{/each}} {{/each}} From 00349740b6433c2760686b2632b77669c329cc2d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Nov 2014 00:44:44 +0100 Subject: [PATCH 086/593] Version bump to 0.4.1 --- bower.json | 2 +- libdist/chartist.js | 238 ++++++++++++++++++++++++++++++--------- libdist/chartist.min.css | 2 +- libdist/chartist.min.js | 4 +- libdist/chartist.min.map | 2 +- package.json | 2 +- 6 files changed, 189 insertions(+), 61 deletions(-) diff --git a/bower.json b/bower.json index 7f139af8..d91474ba 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.4.0", + "version": "0.4.1", "main": [ "./libdist/chartist.min.js", "./libdist/chartist.min.css" diff --git a/libdist/chartist.js b/libdist/chartist.js index ee7fc6cd..e610dc67 100644 --- a/libdist/chartist.js +++ b/libdist/chartist.js @@ -10,7 +10,7 @@ } }(this, function() { - /* Chartist.js 0.4.0 + /* Chartist.js 0.4.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -79,7 +79,7 @@ */ Chartist.stripUnit = function(value) { if(typeof value === 'string') { - value = value.replace(/[^0-9\+-\.]/, ''); + value = value.replace(/[^0-9\+-\.]/g, ''); } return +value; @@ -1097,6 +1097,7 @@ */ function update() { this.createChart(this.optionsProvider.currentOptions); + return this; } /** @@ -1107,6 +1108,7 @@ function detach() { window.removeEventListener('resize', this.resizeListener); this.optionsProvider.removeMediaQueryListeners(); + return this; } /** @@ -1118,6 +1120,7 @@ */ function on(event, handler) { this.eventEmitter.addEventHandler(event, handler); + return this; } /** @@ -1129,6 +1132,7 @@ */ function off(event, handler) { this.eventEmitter.removeEventHandler(event, handler); + return this; } /** @@ -1216,37 +1220,40 @@ * 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. * * @memberof Chartist.Svg - * @param {String} name The name of the SVG element to create + * @constructor + * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg * @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. * @param {String} className This class or class list will be added to the SVG element * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child * @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 - * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ function Svg(name, attributes, className, parent, insertFirst) { - this._node = document.createElementNS(svgNs, name); - - // If this is an SVG element created then custom namespace - if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); - } + // If Svg is getting called with an SVG element we just return the wrapper + if(name instanceof SVGElement) { + this._node = name; + } else { + this._node = document.createElementNS(svgNs, name); - if(attributes) { - this.attr(attributes); - } + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + } - if(className) { - this.addClass(className); - } + if(attributes) { + this.attr(attributes); + } - if(parent) { - if (insertFirst && parent._node.firstChild) { - parent._node.insertBefore(this._node, parent._node.firstChild); - } else { - parent._node.appendChild(this._node); + if(className) { + this.addClass(className); } - this._parent = parent; + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); + } + } } } @@ -1254,11 +1261,19 @@ * Set attributes on the current SVG element of the wrapper you're currently working on. * * @memberof Chartist.Svg - * @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. + * @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. * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {Object} The current wrapper object will be returned so it can be used for chaining. + * @returns {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. */ function attr(attributes, ns) { + if(typeof attributes === 'string') { + if(ns) { + return this._node.getAttributeNS(ns, attributes); + } else { + return this._node.getAttribute(attributes); + } + } + Object.keys(attributes).forEach(function(key) { // If the attribute value is undefined we can skip this one if(attributes[key] === undefined) { @@ -1283,12 +1298,56 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @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 - * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ function elem(name, attributes, className, insertFirst) { return new Chartist.Svg(name, attributes, className, this, insertFirst); } + /** + * Returns the parent Chartist.SVG wrapper object + * + * @returns {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. + */ + function parent() { + return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; + } + + /** + * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. + * + * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element + */ + function root() { + var node = this._node; + while(node.nodeName !== 'svg') { + node = node.parentNode; + } + return new Chartist.Svg(node); + } + + /** + * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found + */ + function querySelector(selector) { + var foundNode = this._node.querySelector(selector); + return foundNode ? new Chartist.Svg(foundNode) : null; + } + + /** + * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found + */ + function querySelectorAll(selector) { + var foundNodes = this._node.querySelectorAll(selector); + return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; + } + /** * 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. * @@ -1297,7 +1356,7 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Object} New wrapper object that wraps the foreignObject element + * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element */ function foreignObject(content, attributes, className, insertFirst) { // If content is string then we convert it to DOM @@ -1326,7 +1385,7 @@ * * @memberof Chartist.Svg * @param {String} t The text that should be added to the text element that is created - * @returns {Object} The same wrapper object that was used to add the newly created element + * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element */ function text(t) { this._node.appendChild(document.createTextNode(t)); @@ -1337,7 +1396,7 @@ * This method will clear all child nodes of the current wrapper object. * * @memberof Chartist.Svg - * @returns {Object} The same wrapper object that got emptied + * @returns {Chartist.Svg} The same wrapper object that got emptied */ function empty() { while (this._node.firstChild) { @@ -1351,24 +1410,22 @@ * 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. * * @memberof Chartist.Svg - * @returns {Object} The parent wrapper object of the element that got removed + * @returns {Chartist.Svg} The parent wrapper object of the element that got removed */ function remove() { this._node.parentNode.removeChild(this._node); - return this._parent; + return new Chartist.Svg(this._node.parentNode); } /** * This method will replace the element with a new element that can be created outside of the current DOM. * * @memberof Chartist.Svg - * @param {Object} newElement The new Chartist.Svg object that will be used to replace the current wrapper object - * @returns {Object} The wrapper of the new element + * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object + * @returns {Chartist.Svg} The wrapper of the new element */ function replace(newElement) { this._node.parentNode.replaceChild(newElement._node, this._node); - newElement._parent = this._parent; - this._parent = null; return newElement; } @@ -1376,9 +1433,9 @@ * This method will append an element to the current element as a child. * * @memberof Chartist.Svg - * @param {Object} element The Chartist.Svg element that should be added as a child + * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Object} The wrapper of the appended object + * @returns {Chartist.Svg} The wrapper of the appended object */ function append(element, insertFirst) { if(insertFirst && this._node.firstChild) { @@ -1405,7 +1462,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element + * @returns {Chartist.Svg} The wrapper of the current element */ function addClass(names) { this._node.setAttribute('class', @@ -1424,7 +1481,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Object} The wrapper of the current element + * @returns {Chartist.Svg} The wrapper of the current element */ function removeClass(names) { var removedClasses = names.trim().split(/\s+/); @@ -1440,10 +1497,12 @@ * Removes all classes from the current element. * * @memberof Chartist.Svg - * @returns {Object} The wrapper of the current element + * @returns {Chartist.Svg} The wrapper of the current element */ function removeAllClasses() { this._node.setAttribute('class', ''); + + return this; } /** @@ -1469,7 +1528,7 @@ } /** - * 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 values specifying a cubic Bézier curve. + * 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. * **An animations object could look like this:** * ```javascript * element.animate({ @@ -1494,10 +1553,12 @@ * **Automatic unit conversion** * 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. * **Guided mode** - * 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. 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. + * 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. * If guided mode is enabled the following behavior is added: * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) * - The animate element will be forced to use `fill="freeze"` + * - 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. * - After the animation the element attribute value will be set to the `to` value of the animation * - The animate element is deleted from the DOM * @@ -1505,7 +1566,7 @@ * @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. * @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. * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. - * @returns {Object} The current element where the animation was added + * @returns {Chartist.Svg} The current element where the animation was added */ function animate(animations, guided, eventEmitter) { if(guided === undefined) { @@ -1517,6 +1578,7 @@ function createAnimate(animationDefinition, guided) { var attributeProperties = {}, animate, + timeout, easing; // Check if an easing is specified in the definition object and delete it from the object as it will not @@ -1529,28 +1591,40 @@ delete animationDefinition.easing; } + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); + + if(easing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = easing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + // Adding "fill: freeze" if we are in guided mode and set initial attribute values if(guided) { animationDefinition.fill = 'freeze'; // Animated property on our element should already be set to the animation from value in guided mode attributeProperties[attribute] = animationDefinition.from; this.attr(attributeProperties); - } - if(easing) { - animationDefinition.calcMode = 'spline'; - animationDefinition.keySplines = easing.join(' '); - animationDefinition.keyTimes = '0;1'; + // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin + // which needs to be in ms aside + timeout = Chartist.stripUnit(animationDefinition.begin || 0); + animationDefinition.begin = 'indefinite'; } - // If numeric dur or begin was provided we assume milli seconds - animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); - animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); - animate = this.elem('animate', Chartist.extend({ attributeName: attribute }, animationDefinition)); + if(guided) { + // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout + setTimeout(function() { + animate._node.beginElement(); + }, timeout); + } + if(eventEmitter) { animate._node.addEventListener('beginEvent', function handleBeginEvent() { eventEmitter.emit('animationBegin', { @@ -1598,6 +1672,10 @@ constructor: Svg, attr: attr, elem: elem, + parent: parent, + root: root, + querySelector: querySelector, + querySelectorAll: querySelectorAll, foreignObject: foreignObject, text: text, empty: empty, @@ -1658,6 +1736,48 @@ Chartist.Svg.Easing = easingCubicBeziers; + /** + * 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. + * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. + * + * @memberof Chartist.Svg + * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) + * @constructor + */ + function SvgList(nodeList) { + var list = this; + + this.svgElements = []; + for(var i = 0; i < nodeList.length; i++) { + this.svgElements.push(new Chartist.Svg(nodeList[i])); + } + + // Add delegation methods for Chartist.Svg + Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { + return ['constructor', + 'parent', + 'querySelector', + 'querySelectorAll', + 'replace', + 'append', + 'classes', + 'height', + 'width'].indexOf(prototypeProperty) === -1; + }).forEach(function(prototypeProperty) { + list[prototypeProperty] = function() { + var args = Array.prototype.slice.call(arguments, 0); + list.svgElements.forEach(function(element) { + Chartist.Svg.prototype[prototypeProperty].apply(element, args); + }); + return list; + }; + }); + } + + Chartist.Svg.List = Chartist.Class.extend({ + constructor: SvgList + }); + }(window, document, Chartist)); ;/** * 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. @@ -1705,11 +1825,13 @@ 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', vertical: 'ct-vertical', horizontal: 'ct-horizontal' } @@ -1728,8 +1850,8 @@ var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing - var labels = this.svg.elem('g'), - grid = this.svg.elem('g'); + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup); Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); @@ -1930,11 +2052,13 @@ * 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', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' * } @@ -2052,9 +2176,11 @@ classNames: { chart: 'ct-chart-bar', label: 'ct-label', + labelGroup: 'ct-labels', series: 'ct-series', bar: 'ct-bar', grid: 'ct-grid', + gridGroup: 'ct-grids', vertical: 'ct-vertical', horizontal: 'ct-horizontal' } @@ -2073,8 +2199,8 @@ var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing - var labels = this.svg.elem('g'), - grid = this.svg.elem('g'), + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup), // Projected 0 point zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); @@ -2206,9 +2332,11 @@ * classNames: { * chart: 'ct-chart-bar', * label: 'ct-label', + * labelGroup: 'ct-labels', * series: 'ct-series', * bar: 'ct-bar', * grid: 'ct-grid', + * gridGroup: 'ct-grids', * vertical: 'ct-vertical', * horizontal: 'ct-horizontal' * } diff --git a/libdist/chartist.min.css b/libdist/chartist.min.css index b19d6893..a9db80f2 100644 --- a/libdist/chartist.min.css +++ b/libdist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.4.0 +/* Chartist.js 0.4.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js index 2c4c9b55..eae0aa26 100644 --- a/libdist/chartist.min.js +++ b/libdist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.4.0 +/* Chartist.js 0.4.1 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.3.1",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;j0?e:null}var d={added:0,removed:0,modified:0},e=c(a,b);return e&&(e.__delta__.summary=d),e},c.catmullRom2bezier=function(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.3.1",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;j0?e:null}var d={added:0,removed:0,modified:0},e=c(a,b);return e&&(e.__delta__.summary=d),e},c.catmullRom2bezier=function(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); //# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map index 098ef2c8..1c4095ee 100644 --- a/libdist/chartist.min.map +++ b/libdist/chartist.min.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18760,"pos":18755,"col":16,"line":493,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18760,"pos":18755,"col":16,"line":493,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","deltaDescriptor","a","b","findDeltasRecursively","descriptor","__delta__","Object","keys","property","hasOwnProperty","subDescriptor","ours","theirs","summary","modified","removed","added","delta","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","name","insertFirst","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","_parent","ns","key","prefix","setAttribute","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","parentNode","newElement","replaceChild","append","classes","getAttribute","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","easing","attributeProperties","Easing","fill","from","calcMode","keySplines","keyTimes","begin","dur","attributeName","params","to","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","seriesGroups","chart","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.4.0\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.3.1';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas\n /**\n * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property\n * where deltas for specific object properties can be found for the given object nesting level. For nested objects the\n * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also\n * contain a __delta__ property with the deltas of their level.\n *\n * @param {Object|Array} a Object that should be used to analyzed delta to object b\n * @param {Object|Array} b The second object where the deltas from a should be analyzed\n * @returns {Object} Delta descriptor object or null\n */\n Chartist.deltaDescriptor = function(a, b) {\n var summary = {\n added: 0,\n removed: 0,\n modified: 0\n };\n\n function findDeltasRecursively(a, b) {\n var descriptor = {\n __delta__: {}\n };\n\n // First check for removed and modified properties\n Object.keys(a).forEach(function(property) {\n if(!b.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'remove',\n property: property,\n ours: a[property]\n };\n summary.removed++;\n } else {\n if(typeof a[property] === 'object') {\n var subDescriptor = findDeltasRecursively(a[property], b[property]);\n if(subDescriptor) {\n descriptor[property] = subDescriptor;\n }\n } else {\n if(a[property] !== b[property]) {\n descriptor.__delta__[property] = {\n type: 'modify',\n property: property,\n ours: a[property],\n theirs: b[property]\n };\n summary.modified++;\n }\n }\n }\n });\n\n // Check for added properties\n Object.keys(b).forEach(function(property) {\n if(!a.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'added',\n property: property,\n theirs: b[property]\n };\n summary.added++;\n }\n });\n\n return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null;\n }\n\n var delta = findDeltasRecursively(a, b);\n if(delta) {\n delta.__delta__.summary = summary;\n }\n\n return delta;\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 }\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 }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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 * @param {String} name The name of the SVG element to create\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 * @returns {Object} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function Svg(name, attributes, className, parent, insertFirst) {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 this._parent = parent;\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} 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} ns If specified, the attributes will be set as namespace attributes with ns as prefix.\n * @returns {Object} The current wrapper object will be returned so it can be used for chaining.\n */\n function attr(attributes, ns) {\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {Object} 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 * 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 * @returns {Object} 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', xhtmlNs);\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 * @returns {Object} 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 * @returns {Object} 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 * @returns {Object} 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 {Object} newElement The new Chartist.Svg object that will be used to replace the current wrapper object\n * @returns {Object} The wrapper of the new element\n */\n function replace(newElement) {\n this._node.parentNode.replaceChild(newElement._node, this._node);\n newElement._parent = this._parent;\n this._parent = null;\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 {Object} 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 * @returns {Object} 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 * @returns {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 * @returns {Object} 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 * @returns {Object} 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 * @returns {Object} The wrapper of the current element\n */\n function removeAllClasses() {\n this._node.setAttribute('class', '');\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 values 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. 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 * - The animate element will be forced to use `fill=\"freeze\"`\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 * @returns {Object} 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 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 // 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\n if(easing) {\n animationDefinition.calcMode = 'spline';\n animationDefinition.keySplines = easing.join(' ');\n animationDefinition.keyTimes = '0;1';\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 animate = this.elem('animate', Chartist.extend({\n attributeName: attribute\n }, animationDefinition));\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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 }(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g');\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * series: 'ct-series',\n * line: 'ct-line',\n * point: 'ct-point',\n * area: 'ct-area',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\n label: 'ct-label',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g'),\n grid = this.svg.elem('g'),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\n * label: 'ct-label',\n * series: 'ct-series',\n * bar: 'ct-bar',\n * grid: 'ct-grid',\n * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18761,"pos":18756,"col":16,"line":493,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18761,"pos":18756,"col":16,"line":493,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","deltaDescriptor","a","b","findDeltasRecursively","descriptor","__delta__","Object","keys","property","hasOwnProperty","subDescriptor","ours","theirs","summary","modified","removed","added","delta","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":";;;;;;CAAC,SAASA,EAAMC,GACU,gBAAZC,SACNC,OAAOD,QAAUD,IAEK,kBAAXG,SAAyBA,OAAOC,IAC3CD,UAAWH,GAGXD,EAAe,SAAIC,KAEzBK,KAAM,WAYN,GAAIC,KAimFJ,OAhmFAA,GAASC,QAAU,QAElB,SAAUC,EAAQC,EAAUH,GAC3B,YASAA,GAASI,KAAO,SAAUC,GACxB,MAAOA,IAUTL,EAASM,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAYtCL,EAASS,OAAS,SAAUC,EAAQC,GAClCD,EAASA,KACT,KAAK,GAAIE,KAAQD,GAEbD,EAAOE,GADmB,gBAAjBD,GAAOC,GACDZ,EAASS,OAAOC,EAAOE,GAAOD,EAAOC,IAErCD,EAAOC,EAG1B,OAAOF,IAUTV,EAASa,UAAY,SAASC,GAK5B,MAJoB,gBAAVA,KACRA,EAAQA,EAAMC,QAAQ,eAAgB,MAGhCD,GAWVd,EAASgB,WAAa,SAASF,EAAOG,GAKpC,MAJoB,gBAAVH,KACRA,GAAgBG,GAGXH,GAUTd,EAASkB,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQhB,EAASe,cAAcC,IAahEnB,EAASqB,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIC,EAqBJ,OAnBAH,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAEnBE,EAAMJ,EAAUJ,cAAc,OAC3BQ,GACDJ,EAAUK,YAAYD,GAIxBA,EAAM,GAAI1B,GAAS4B,IAAI,OAAOC,MAC5BN,MAAOA,EACPC,OAAQA,IACPM,SAASL,GAAWI,MACrBE,MAAO,UAAYR,EAAQ,aAAeC,EAAS,MAIrDF,EAAUU,YAAYN,EAAIO,OAEnBP,GAUT1B,EAASkC,aAAe,SAAUC,GAGhC,IAAK,GAFDC,MAEKC,EAAI,EAAGA,EAAIF,EAAKG,OAAOC,OAAQF,IAAK,CAG3CD,EAAMC,GAAgC,gBAApBF,GAAKG,OAAOD,IAA4CG,SAAxBL,EAAKG,OAAOD,GAAGF,KAC/DA,EAAKG,OAAOD,GAAGF,KAAOA,EAAKG,OAAOD,EAGpC,KAAK,GAAII,GAAI,EAAGA,EAAIL,EAAMC,GAAGE,OAAQE,IACnCL,EAAMC,GAAGI,IAAML,EAAMC,GAAGI,GAI5B,MAAOL,IAWTpC,EAAS0C,mBAAqB,SAAUC,EAAWJ,GACjD,IAAK,GAAIF,GAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IACpC,GAAIM,EAAUN,GAAGE,SAAWA,EAI5B,IAAK,GAAIE,GAAIE,EAAUN,GAAGE,OAAYA,EAAJE,EAAYA,IAC5CE,EAAUN,GAAGI,GAAK,CAItB,OAAOE,IAUT3C,EAAS4C,iBAAmB,SAAU9B,GACpC,MAAO+B,MAAKC,MAAMD,KAAKE,IAAIF,KAAKG,IAAIlC,IAAU+B,KAAKI,OAarDjD,EAASkD,cAAgB,SAAUxB,EAAKa,EAAQY,EAAQC,GACtD,GAAIC,GAAkBrD,EAASsD,mBAAmB5B,EAAK0B,EACvD,OAAQb,GAASY,EAAOI,MAAQF,GAWlCrD,EAASsD,mBAAqB,SAAU5B,EAAK0B,GAC3C,MAAOP,MAAKW,KAAKxD,EAASa,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAoC,EAAvB4B,EAAQK,aAAoBL,EAAQM,MAAMC,OAAQ,IAU5H3D,EAAS4D,WAAa,SAAUjB,GAC9B,GAAIN,GACFI,EACAoB,GACEC,MAAOC,OAAOC,UACdC,IAAKF,OAAOC,UAGhB,KAAK3B,EAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IAChC,IAAKI,EAAI,EAAGA,EAAIE,EAAUN,GAAGE,OAAQE,IAC/BE,EAAUN,GAAGI,GAAKoB,EAAQC,OAC5BD,EAAQC,KAAOnB,EAAUN,GAAGI,IAG1BE,EAAUN,GAAGI,GAAKoB,EAAQI,MAC5BJ,EAAQI,IAAMtB,EAAUN,GAAGI,GAKjC,OAAOoB,IAcT7D,EAASkE,UAAY,SAAUxC,EAAKyC,EAAgBf,EAASgB,GAC3D,GAAI/B,GACFgC,EACAC,EACAnB,EAASnD,EAAS4D,WAAWO,EAG/BhB,GAAOW,MAAQV,EAAQU,OAA0B,IAAjBV,EAAQU,KAAa,EAAIX,EAAOW,MAChEX,EAAOc,KAAOb,EAAQa,MAAwB,IAAhBb,EAAQa,IAAY,EAAId,EAAOc,KAI1Dd,EAAOW,OAASX,EAAOc,MAEN,IAAfd,EAAOc,IACRd,EAAOW,KAAO,EACNX,EAAOc,IAAM,EAErBd,EAAOW,KAAO,EAGdX,EAAOc,IAAM,IAObG,GAAqC,IAAnBA,KACpBjB,EAAOW,KAAOjB,KAAKW,IAAIY,EAAgBjB,EAAOW,MAC9CX,EAAOc,IAAMpB,KAAK0B,IAAIH,EAAgBjB,EAAOc,MAG/Cd,EAAOqB,WAAarB,EAAOW,KAAOX,EAAOc,IACzCd,EAAOsB,IAAMzE,EAAS4C,iBAAiBO,EAAOqB,YAC9CrB,EAAOoB,IAAM1B,KAAKC,MAAMK,EAAOc,IAAMpB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOK,IAAMX,KAAK8B,KAAKxB,EAAOW,KAAOjB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IACnCpB,EAAOyB,KAAO/B,KAAK6B,IAAI,GAAIvB,EAAOsB,KAClCtB,EAAO0B,cAAgBhC,KAAKiC,MAAM3B,EAAOI,MAAQJ,EAAOyB,KAOxD,KAHA,GAAIrC,GAASvC,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,GAC5D2B,EAAUxC,EAASa,EAAQ4B,MAAMC,gBAGjC,GAAIF,GAAW/E,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,IAAYA,EAAQ4B,MAAMC,cACxF9B,EAAOyB,MAAQ,MACV,CAAA,GAAKG,KAAW/E,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAO,EAAGzB,EAAQC,IAAYA,EAAQ4B,MAAMC,eAGpG,KAFA9B,GAAOyB,MAAQ,EASnB,IAFAP,EAASlB,EAAOoB,IAChBD,EAASnB,EAAOK,IACXnB,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAC5CvC,EAAIc,EAAOyB,KAAOzB,EAAOc,MAC3BI,GAAUlB,EAAOyB,MAGfvC,EAAIc,EAAOyB,MAAQzB,EAAOW,OAC5BQ,GAAUnB,EAAOyB,KAQrB,KALAzB,EAAOoB,IAAMF,EACblB,EAAOK,IAAMc,EACbnB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IAEnCpB,EAAO+B,UACF7C,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAChDzB,EAAO+B,OAAOC,KAAK9C,EAGrB,OAAOc,IAaTnD,EAASoF,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAM3C,KAAK6C,GAAK,GAEvD,QACEC,EAAGN,EAAWE,EAAS1C,KAAK+C,IAAIH,GAChCI,EAAGP,EAAWC,EAAS1C,KAAKiD,IAAIL,KAYpCzF,EAAS+F,gBAAkB,SAAUrE,EAAK0B,GACxC,GAAI4C,GAAU5C,EAAQ4B,MAAQ5B,EAAQ4B,MAAMrB,OAAS,EACnDsC,EAAU7C,EAAQM,MAAQN,EAAQM,MAAMC,OAAS,CAEnD,QACEuC,GAAI9C,EAAQK,aAAeuC,EAC3BG,GAAItD,KAAKW,KAAKxD,EAASa,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAY4B,EAAQK,aAAewC,EAAS7C,EAAQK,cAC5G2C,GAAIvD,KAAKW,KAAKxD,EAASa,UAAUuC,EAAQ7B,QAAUG,EAAIH,SAAW6B,EAAQK,aAAcL,EAAQK,aAAeuC,GAC/GK,GAAIjD,EAAQK,aACZlC,MAAO,WACL,MAAOxB,MAAKqG,GAAKrG,KAAKmG,IAExB1E,OAAQ,WACN,MAAOzB,MAAKoG,GAAKpG,KAAKsG,MAe5BrG,EAASsG,YAAc,SAASC,EAAQC,EAAMC,EAAYhF,EAAWiF,GACnE,GAAGA,EAAuB,CACxB,GAAIC,GAAU,gBAAkBlF,EAAY,KAAO+E,EAAO,SAC1D,OAAOD,GAAOK,cAAcD,EAASF,GAErC,MAAOF,GAAOM,KAAK,OAAQJ,EAAYhF,GAAW+E,KAAKA,IAgB3DxG,EAAS8G,YAAc,SAAUC,EAAW5E,EAAM6E,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAErFvE,EAAK8E,OAAOE,QAAQ,SAAUrG,EAAOsG,GACnC,GAAIC,GAAoBjE,EAAQM,MAAM4D,sBAAsBxG,EAAOsG,GACjE7F,EAAQwF,EAAUxF,QAAUY,EAAK8E,OAAO1E,OACxCf,EAAS4B,EAAQM,MAAMC,OACvB4D,EAAMR,EAAUb,GAAK3E,EAAQ6F,CAG/B,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIjE,EAAQM,MAAM8D,SAAU,CAC1B,GAAIC,GAAcT,EAAKH,KAAK,QAC1BX,GAAIqB,EACJpB,GAAIY,EAAUZ,GACdC,GAAImB,EACJlB,GAAIU,EAAUV,KACZjD,EAAQsE,WAAWV,KAAM5D,EAAQsE,WAAWC,YAAYC,KAAK,KAGjEV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTvB,GAAIqB,EACJpB,GAAIY,EAAUZ,GACdC,GAAImB,EACJlB,GAAIU,EAAUV,KAIlB,GAAIjD,EAAQM,MAAMwE,UAAW,CAC3B,GAAIC,IACFxC,EAAG4B,EAAMnE,EAAQM,MAAM0E,YAAYzC,EACnCE,EAAGkB,EAAUZ,GAAK/C,EAAQM,MAAM0E,YAAYvC,GAAKa,EAAwB,EAAI,KAG3E2B,EAAerI,EAASsG,YAAYW,EAAQ,GAAKI,GACnD1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQsE,WAAWY,MAAOlF,EAAQsE,WAAWC,YAAYC,KAAK,KAAMlB,EAExEQ,GAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EAER+G,GAAIC,SAEF,MADAtI,GAAOuI,QAAQC,KAAK,mEACb3I,KAAKwB,cAmBtBvB,EAAS2I,YAAc,SAAU5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAEvFvD,EAAO+B,OAAOiC,QAAQ,SAAUrG,EAAOsG,GACrC,GAAIC,GAAoBjE,EAAQ4B,MAAMsC,sBAAsBxG,EAAOsG,GACjE7F,EAAQ6B,EAAQ4B,MAAMrB,OACtBnC,EAASuF,EAAUvF,SAAW2B,EAAO+B,OAAO3C,OAC5CgF,EAAMR,EAAUZ,GAAK3E,EAAS4F,CAGhC,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIjE,EAAQ4B,MAAMwC,SAAU,CAC1B,GAAIC,GAAcT,EAAKH,KAAK,QAC1BX,GAAIa,EAAUb,GACdC,GAAIoB,EACJnB,GAAIW,EAAUX,GACdC,GAAIkB,IACFnE,EAAQsE,WAAWV,KAAM5D,EAAQsE,WAAWkB,UAAUhB,KAAK,KAG/DV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTvB,GAAIa,EAAUb,GACdC,GAAIoB,EACJnB,GAAIW,EAAUX,GACdC,GAAIkB,IAIR,GAAInE,EAAQ4B,MAAMkD,UAAW,CAC3B,GAAIC,IACFxC,EAAGvC,EAAQK,aAAeL,EAAQ4B,MAAMoD,YAAYzC,GAAKe,EAAwB,IAAM,GACvFb,EAAG0B,EAAMnE,EAAQ4B,MAAMoD,YAAYvC,GAAKa,EAAwB,IAAM,IAGpE2B,EAAerI,EAASsG,YAAYW,EAAQ,GAAKI,GACnD1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQsE,WAAWY,MAAOlF,EAAQsE,WAAWkB,UAAUhB,KAAK,KAAMlB,EAEtEQ,GAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EAER+G,GAAIC,SAEF,MADAtI,GAAOuI,QAAQC,KAAK,mEACb3I,KAAKyB,eAiBtBxB,EAAS6I,aAAe,SAAU9B,EAAW5D,EAAQhB,EAAMiF,GACzD,OACEzB,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAUY,EAAKI,OAAS6E,EACpDvB,EAAGkB,EAAUZ,GAAKY,EAAUvF,UAAYW,EAAKiF,GAASjE,EAAOoB,MAAQpB,EAAOI,MAAQJ,EAAOyB,QAe/F5E,EAAS8I,gBAAkB,SAAUC,EAAgB3F,EAAS4F,EAAmB9B,GAM/E,QAAS+B,KACP,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiBnJ,EAASS,UAAW2I,GAEjCJ,EACF,IAAK3G,EAAI,EAAGA,EAAI2G,EAAkBzG,OAAQF,IAAK,CAC7C,GAAIgH,GAAMnJ,EAAOoJ,WAAWN,EAAkB3G,GAAG,GAC7CgH,GAAIE,UACNJ,EAAiBnJ,EAASS,OAAO0I,EAAgBH,EAAkB3G,GAAG,KAKzE6E,GACDA,EAAaW,KAAK,kBAChBqB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoBtC,QAAQ,SAASkC,GACnCA,EAAIK,eAAeT,KA5BvB,GACEE,GAEA9G,EAHE+G,EAAcpJ,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GAErEqG,IA8BF,KAAKvJ,EAAOoJ,WACV,KAAM,iEACD,IAAIN,EAET,IAAK3G,EAAI,EAAGA,EAAI2G,EAAkBzG,OAAQF,IAAK,CAC7C,GAAIgH,GAAMnJ,EAAOoJ,WAAWN,EAAkB3G,GAAG,GACjDgH,GAAIM,YAAYV,GAChBQ,EAAoBtE,KAAKkE,GAM7B,MAFAJ,MAGEV,GAAIY,kBACF,MAAOnJ,GAASS,UAAW0I,IAE7BK,0BAA2BA,IAe/BxJ,EAAS4J,gBAAkB,SAASC,EAAGC,GAOrC,QAASC,GAAsBF,EAAGC,GAChC,GAAIE,IACFC,aA4CF,OAxCAC,QAAOC,KAAKN,GAAG1C,QAAQ,SAASiD,GAC9B,GAAIN,EAAEO,eAAeD,GAQnB,GAA0B,gBAAhBP,GAAEO,GAAwB,CAClC,GAAIE,GAAgBP,EAAsBF,EAAEO,GAAWN,EAAEM,GACtDE,KACDN,EAAWI,GAAYE,OAGtBT,GAAEO,KAAcN,EAAEM,KACnBJ,EAAWC,UAAUG,IACnBtC,KAAM,SACNsC,SAAUA,EACVG,KAAMV,EAAEO,GACRI,OAAQV,EAAEM,IAEZK,EAAQC,gBApBZV,GAAWC,UAAUG,IACnBtC,KAAM,SACNsC,SAAUA,EACVG,KAAMV,EAAEO,IAEVK,EAAQE,YAsBZT,OAAOC,KAAKL,GAAG3C,QAAQ,SAASiD,GAC1BP,EAAEQ,eAAeD,KACnBJ,EAAWC,UAAUG,IACnBtC,KAAM,QACNsC,SAAUA,EACVI,OAAQV,EAAEM,IAEZK,EAAQG,WAI+B,IAAnCV,OAAOC,KAAKH,GAAYzH,QAAgB2H,OAAOC,KAAKH,EAAWC,WAAW1H,OAAS,EAAKyH,EAAa,KApD/G,GAAIS,IACFG,MAAO,EACPD,QAAS,EACTD,SAAU,GAoDRG,EAAQd,EAAsBF,EAAGC,EAKrC,OAJGe,KACDA,EAAMZ,UAAUQ,QAAUA,GAGrBI,GAIT7K,EAAS8K,kBAAoB,SAAUC,EAAKC,GAE1C,IAAK,GADDC,MACK5I,EAAI,EAAG6I,EAAOH,EAAIxI,OAAQ2I,EAAO,GAAKF,EAAI3I,EAAGA,GAAK,EAAG,CAC5D,GAAI8I,KACDxF,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,KAC5BsD,GAAIoF,EAAI1I,GAAIwD,GAAIkF,EAAI1I,EAAI,KACxBsD,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,KAC5BsD,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,IAE3B2I,GACG3I,EAEM6I,EAAO,IAAM7I,EACtB8I,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,IACnBG,EAAO,IAAM7I,IACtB8I,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,IAC5BI,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,KAL5BI,EAAE,IAAMxF,GAAIoF,EAAIG,EAAO,GAAIrF,GAAIkF,EAAIG,EAAO,IAQxCA,EAAO,IAAM7I,EACf8I,EAAE,GAAKA,EAAE,GACC9I,IACV8I,EAAE,IAAMxF,GAAIoF,EAAI1I,GAAIwD,GAAIkF,EAAI1I,EAAI,KAGpC4I,EAAE9F,QAEIgG,EAAE,GAAGxF,EAAI,EAAIwF,EAAE,GAAGxF,EAAIwF,EAAE,GAAGxF,GAAK,IAChCwF,EAAE,GAAGtF,EAAI,EAAIsF,EAAE,GAAGtF,EAAIsF,EAAE,GAAGtF,GAAK,GACjCsF,EAAE,GAAGxF,EAAI,EAAIwF,EAAE,GAAGxF,EAAIwF,EAAE,GAAGxF,GAAK,GAChCwF,EAAE,GAAGtF,EAAI,EAAIsF,EAAE,GAAGtF,EAAIsF,EAAE,GAAGtF,GAAK,EACjCsF,EAAE,GAAGxF,EACLwF,EAAE,GAAGtF,IAKX,MAAOoF,KAGT/K,OAAQC,SAAUH,GAOnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAASoL,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAOnG,KAAKoG,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAO/I,cACViJ,GAASF,UAIXE,GAASF,IAYtB,QAASzD,GAAKyD,EAAOnJ,GAEhBqJ,EAASF,IACVE,EAASF,GAAOnE,QAAQ,SAASoE,GAC/BA,EAAQpJ,KAKTqJ,EAAS,MACVA,EAAS,KAAKrE,QAAQ,SAASyE,GAC7BA,EAAYN,EAAOnJ,KAvDzB,GAAIqJ,KA4DJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpB5D,KAAMA,KAIV3H,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAAS6L,GAAYC,GACnB,GAAIC,KACJ,IAAID,EAAKvJ,OACP,IAAK,GAAIF,GAAI,EAAGA,EAAIyJ,EAAKvJ,OAAQF,IAC/B0J,EAAI5G,KAAK2G,EAAKzJ,GAGlB,OAAO0J,GA4CT,QAAStL,GAAOuL,EAAYC,GAC1B,GAAIC,GAAaD,GAAsBlM,KAAKoM,WAAanM,EAASoM,MAC9DC,EAAQnC,OAAOoC,OAAOJ,EAE1BlM,GAASoM,MAAMG,iBAAiBF,EAAOL,EAEvC,IAAIQ,GAAS,WACX,GACEC,GADEC,EAAKL,EAAMM,aAAe,YAU9B,OALAF,GAAW1M,OAASC,EAAWkK,OAAOoC,OAAOD,GAAStM,KACtD2M,EAAGE,MAAMH,EAAUI,MAAMV,UAAUW,MAAMC,KAAKC,UAAW,IAIlDP,EAOT,OAJAD,GAAOL,UAAYE,EACnBG,EAAOS,MAAQf,EACfM,EAAO/L,OAASV,KAAKU,OAEd+L,EA0FT,QAASU,GAAIC,EAAanB,GACxB,GAAGjM,OAASC,EAASoM,MACnB,KAAM,IAAIgB,OAAM,iFAIlB,IAAIC,QACDC,OAAOH,GACPI,IAAI,SAAUpB,GACb,MAAOA,aAAqBqB,UAAWrB,EAAUA,UAAYA,IAG7DsB,EAAkBzN,EAASoM,MAAMG,iBAAiBK,MAAMpK,OAAW6K,EAGvE,cADOI,GAAgBd,YAChB5M,KAAKU,OAAOuL,EAAYyB,GAIjC,QAASlB,KACP,GAAImB,GAAO7B,EAAYmB,WACnBtM,EAASgN,EAAK,EAYlB,OAVAA,GAAKhC,OAAO,EAAGgC,EAAKnL,OAAS,GAAG4E,QAAQ,SAAUxG,GAChDuJ,OAAOyD,oBAAoBhN,GAAQwG,QAAQ,SAAUyG,SAE5ClN,GAAOkN,GAEd1D,OAAO2D,eAAenN,EAAQkN,EAC5B1D,OAAO4D,yBAAyBnN,EAAQiN,QAIvClN,EAGTV,EAASoM,OACP3L,OAAQA,EACRyM,IAAKA,EACLX,iBAAkBA,IAGpBrM,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAaA,SAAS+N,KAEP,MADAhO,MAAKiO,YAAYjO,KAAK+I,gBAAgBK,gBAC/BpJ,KAQT,QAASkO,KAGP,MAFA/N,GAAOgO,oBAAoB,SAAUnO,KAAKoO,gBAC1CpO,KAAK+I,gBAAgBU,4BACdzJ,KAUT,QAASqO,GAAG9C,EAAOC,GAEjB,MADAxL,MAAKmH,aAAamE,gBAAgBC,EAAOC,GAClCxL,KAUT,QAASsO,GAAI/C,EAAOC,GAElB,MADAxL,MAAKmH,aAAauE,mBAAmBH,EAAOC,GACrCxL,KAYT,QAASuO,GAAKnN,EAAOgB,EAAMiB,EAAS4F,GAClCjJ,KAAKuB,UAAYtB,EAASkB,cAAcC,GACxCpB,KAAKoC,KAAOA,EACZpC,KAAKqD,QAAUA,EACfrD,KAAKiJ,kBAAoBA,EACzBjJ,KAAKmH,aAAelH,EAASoL,eAC7BrL,KAAK2G,sBAAwB1G,EAAS4B,IAAI2M,YAAY,iBACtDxO,KAAKyO,mBAAqBxO,EAAS4B,IAAI2M,YAAY,4BACnDxO,KAAKoO,eAAiB,WACpBpO,KAAKgO,UACLU,KAAK1O,MAEJA,KAAKuB,YAEHvB,KAAKuB,UAAUoN,cAChB3O,KAAKuB,UAAUoN,aAAaT,SAG9BlO,KAAKuB,UAAUoN,aAAe3O,MAGhCG,EAAOyO,iBAAiB,SAAU5O,KAAKoO,gBAIvCS,WAAW,WAIT7O,KAAK+I,gBAAkB9I,EAAS8I,mBAAoB/I,KAAKqD,QAASrD,KAAKiJ,kBAAmBjJ,KAAKmH,cAC/FnH,KAAKiO,YAAYjO,KAAK+I,gBAAgBK,iBACtCsF,KAAK1O,MAAO,GAIhBC,EAASsO,KAAOtO,EAASoM,MAAM3L,QAC7BkM,YAAa2B,EACbxF,gBAAiBtG,OACjBlB,UAAWkB,OACXd,IAAKc,OACL0E,aAAc1E,OACdwL,YAAa,WACX,KAAM,IAAIZ,OAAM,2CAElBW,OAAQA,EACRE,OAAQA,EACRG,GAAIA,EACJC,IAAKA,EACLpO,QAASD,EAASC,QAClByG,uBAAuB,KAGzBxG,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAuBA,SAAS4B,GAAIiN,EAAMpI,EAAYhF,EAAW8E,EAAQuI,GAE7CD,YAAgBE,YACjBhP,KAAKkC,MAAQ4M,GAEb9O,KAAKkC,MAAQ9B,EAAS6O,gBAAgBC,EAAOJ,GAGjC,QAATA,GACD9O,KAAKkC,MAAMiN,eAAeC,EAAOnP,EAASmP,MAAMC,cAAepP,EAASmP,MAAME,KAG7E5I,GACD1G,KAAK8B,KAAK4E,GAGThF,GACD1B,KAAK+B,SAASL,GAGb8E,IACGuI,GAAevI,EAAOtE,MAAMqN,WAC9B/I,EAAOtE,MAAMsN,aAAaxP,KAAKkC,MAAOsE,EAAOtE,MAAMqN,YAEnD/I,EAAOtE,MAAMD,YAAYjC,KAAKkC,SActC,QAASJ,GAAK4E,EAAY+I,GACxB,MAAyB,gBAAf/I,GACL+I,EACMzP,KAAKkC,MAAMwN,eAAeD,EAAI/I,GAE9B1G,KAAKkC,MAAMyN,aAAajJ,IAInCyD,OAAOC,KAAK1D,GAAYU,QAAQ,SAASwI,GAEhBnN,SAApBiE,EAAWkJ,KAIXH,EACDzP,KAAKkC,MAAMiN,eAAeM,GAAKxP,EAASmP,MAAMS,OAAQ,IAAKD,GAAK/H,KAAK,IAAKnB,EAAWkJ,IAErF5P,KAAKkC,MAAM4N,aAAaF,EAAKlJ,EAAWkJ,MAE1ClB,KAAK1O,OAEAA,MAaT,QAAS8G,GAAKgI,EAAMpI,EAAYhF,EAAWqN,GACzC,MAAO,IAAI9O,GAAS4B,IAAIiN,EAAMpI,EAAYhF,EAAW1B,KAAM+O,GAQ7D,QAASvI,KACP,MAAOxG,MAAKkC,MAAM6N,qBAAsBf,YAAa,GAAI/O,GAAS4B,IAAI7B,KAAKkC,MAAM6N,YAAc,KAQjG,QAASrQ,KAEP,IADA,GAAIsQ,GAAOhQ,KAAKkC,MACQ,QAAlB8N,EAAKC,UACTD,EAAOA,EAAKD,UAEd,OAAO,IAAI9P,GAAS4B,IAAImO,GAS1B,QAAS7O,GAAc+O,GACrB,GAAIC,GAAYnQ,KAAKkC,MAAMf,cAAc+O,EACzC,OAAOC,GAAY,GAAIlQ,GAAS4B,IAAIsO,GAAa,KASnD,QAASC,GAAiBF,GACxB,GAAIG,GAAarQ,KAAKkC,MAAMkO,iBAAiBF,EAC7C,OAAOG,GAAW7N,OAAS,GAAIvC,GAAS4B,IAAIyO,KAAKD,GAAc,KAajE,QAASxJ,GAAcD,EAASF,EAAYhF,EAAWqN,GAGrD,GAAsB,gBAAZnI,GAAsB,CAC9B,GAAIrF,GAAYnB,EAASmQ,cAAc,MACvChP,GAAUiP,UAAY5J,EACtBA,EAAUrF,EAAUgO,WAItB3I,EAAQkJ,aAAa,QAASW,EAI9B,IAAIC,GAAQ1Q,KAAK8G,KAAK,gBAAiBJ,EAAYhF,EAAWqN,EAK9D,OAFA2B,GAAMxO,MAAMD,YAAY2E,GAEjB8J,EAUT,QAASjK,GAAKkK,GAEZ,MADA3Q,MAAKkC,MAAMD,YAAY7B,EAASwQ,eAAeD,IACxC3Q,KAST,QAAS6Q,KACP,KAAO7Q,KAAKkC,MAAMqN,YAChBvP,KAAKkC,MAAMN,YAAY5B,KAAKkC,MAAMqN,WAGpC,OAAOvP,MAST,QAAS8Q,KAEP,MADA9Q,MAAKkC,MAAM6N,WAAWnO,YAAY5B,KAAKkC,OAChC,GAAIjC,GAAS4B,IAAI7B,KAAKkC,MAAM6N,YAUrC,QAAS/O,GAAQ+P,GAEf,MADA/Q,MAAKkC,MAAM6N,WAAWiB,aAAaD,EAAW7O,MAAOlC,KAAKkC,OACnD6O,EAWT,QAASE,GAAO/I,EAAS6G,GAOvB,MANGA,IAAe/O,KAAKkC,MAAMqN,WAC3BvP,KAAKkC,MAAMsN,aAAatH,EAAQhG,MAAOlC,KAAKkC,MAAMqN,YAElDvP,KAAKkC,MAAMD,YAAYiG,EAAQhG,OAG1BlC,KAST,QAASkR,KACP,MAAOlR,MAAKkC,MAAMyN,aAAa,SAAW3P,KAAKkC,MAAMyN,aAAa,SAASwB,OAAOC,MAAM,UAU1F,QAASrP,GAASsP,GAShB,MARArR,MAAKkC,MAAM4N,aAAa,QACtB9P,KAAKkR,QAAQlR,KAAKkC,OACfqL,OAAO8D,EAAMF,OAAOC,MAAM,QAC1BE,OAAO,SAASxK,EAAMU,EAAK+J,GAC1B,MAAOA,GAAK3F,QAAQ9E,KAAUU,IAC7BK,KAAK,MAGL7H,KAUT,QAASwR,GAAYH,GACnB,GAAII,GAAiBJ,EAAMF,OAAOC,MAAM,MAMxC,OAJApR,MAAKkC,MAAM4N,aAAa,QAAS9P,KAAKkR,QAAQlR,KAAKkC,OAAOoP,OAAO,SAASxC,GACxE,MAAwC,KAAjC2C,EAAe7F,QAAQkD,KAC7BjH,KAAK,MAED7H,KAST,QAAS0R,KAGP,MAFA1R,MAAKkC,MAAM4N,aAAa,QAAS,IAE1B9P,KAUT,QAASyB,KACP,MAAOzB,MAAKkC,MAAMyP,cAAgB7O,KAAKiC,MAAM/E,KAAKkC,MAAM0P,UAAUnQ,SAAWzB,KAAKkC,MAAM6N,WAAW4B,aAUrG,QAASnQ,KACP,MAAOxB,MAAKkC,MAAM2P,aAAe/O,KAAKiC,MAAM/E,KAAKkC,MAAM0P,UAAUpQ,QAAUxB,KAAKkC,MAAM6N,WAAW8B,YA4CnG,QAASC,GAAQC,EAAYC,EAAQ7K,GAiGnC,MAhGc1E,UAAXuP,IACDA,GAAS,GAGX7H,OAAOC,KAAK2H,GAAY3K,QAAQ,SAAoC6K,GAElE,QAASC,GAAcC,EAAqBH,GAC1C,GACEF,GACAM,EACAC,EAHEC,IAODH,GAAoBE,SAErBA,EAASF,EAAoBE,iBAAkBvF,OAC7CqF,EAAoBE,OACpBpS,EAAS4B,IAAI0Q,OAAOJ,EAAoBE,cACnCF,GAAoBE,QAI7BF,EAAoBK,MAAQvS,EAASgB,WAAWkR,EAAoBK,MAAO,MAC3EL,EAAoBM,IAAMxS,EAASgB,WAAWkR,EAAoBM,IAAK,MAEpEJ,IACDF,EAAoBO,SAAW,SAC/BP,EAAoBQ,WAAaN,EAAOxK,KAAK,KAC7CsK,EAAoBS,SAAW,OAI9BZ,IACDG,EAAoBU,KAAO,SAE3BP,EAAoBL,GAAaE,EAAoBW,KACrD9S,KAAK8B,KAAKwQ,GAIVF,EAAUnS,EAASa,UAAUqR,EAAoBK,OAAS,GAC1DL,EAAoBK,MAAQ,cAG9BV,EAAU9R,KAAK8G,KAAK,UAAW7G,EAASS,QACtCqS,cAAed,GACdE,IAEAH,GAEDnD,WAAW,WACTiD,EAAQ5P,MAAM8Q,gBACbZ,GAGFjL,GACD2K,EAAQ5P,MAAM0M,iBAAiB,aAAc,WAC3CzH,EAAaW,KAAK,kBAChBI,QAASlI,KACT8R,QAASA,EAAQ5P,MACjB+Q,OAAQd,KAEVzD,KAAK1O,OAGT8R,EAAQ5P,MAAM0M,iBAAiB,WAAY,WACtCzH,GACDA,EAAaW,KAAK,gBAChBI,QAASlI,KACT8R,QAASA,EAAQ5P,MACjB+Q,OAAQd,IAITH,IAEDM,EAAoBL,GAAaE,EAAoBe,GACrDlT,KAAK8B,KAAKwQ,GAEVR,EAAQhB,WAEVpC,KAAK1O,OAIN+R,EAAWE,YAAsBnF,OAClCiF,EAAWE,GAAW7K,QAAQ,SAAS+K,GACrCD,EAAcxD,KAAK1O,MAAMmS,GAAqB,IAC9CzD,KAAK1O,OAEPkS,EAAcxD,KAAK1O,MAAM+R,EAAWE,GAAYD,IAGlDtD,KAAK1O,OAEAA,KA+ET,QAASmT,GAAQC,GACf,GAAIrH,GAAO/L,IAEXA,MAAKqT,cACL,KAAI,GAAI/Q,GAAI,EAAGA,EAAI8Q,EAAS5Q,OAAQF,IAClCtC,KAAKqT,YAAYjO,KAAK,GAAInF,GAAS4B,IAAIuR,EAAS9Q,IAIlD6H,QAAOC,KAAKnK,EAAS4B,IAAIuK,WAAWkF,OAAO,SAASgC,GAClD,MAQ4C,MARpC,cACJ,SACA,gBACA,mBACA,UACA,SACA,UACA,SACA,SAAS1H,QAAQ0H,KACpBlM,QAAQ,SAASkM,GAClBvH,EAAKuH,GAAqB,WACxB,GAAI3F,GAAOb,MAAMV,UAAUW,MAAMC,KAAKC,UAAW,EAIjD,OAHAlB,GAAKsH,YAAYjM,QAAQ,SAASc,GAChCjI,EAAS4B,IAAIuK,UAAUkH,GAAmBzG,MAAM3E,EAASyF,KAEpD5B,KAnjBb,GAAImD,GAAQ,6BACVE,EAAQ,gCACRqB,EAAU,8BAEZxQ,GAASmP,OACPC,cAAe,WACfQ,OAAQ,KACRP,IAAK,6CAucPrP,EAAS4B,IAAM5B,EAASoM,MAAM3L,QAC5BkM,YAAa/K,EACbC,KAAMA,EACNgF,KAAMA,EACNN,OAAQA,EACR9G,KAAMA,EACNyB,cAAeA,EACfiP,iBAAkBA,EAClBvJ,cAAeA,EACfJ,KAAMA,EACNoK,MAAOA,EACPC,OAAQA,EACR9P,QAASA,EACTiQ,OAAQA,EACRC,QAASA,EACTnP,SAAUA,EACVyP,YAAaA,EACbE,iBAAkBA,EAClBjQ,OAAQA,EACRD,MAAOA,EACPsQ,QAASA,IAUX7R,EAAS4B,IAAI2M,YAAc,SAAS+E,GAClC,MAAOnT,GAASoT,eAAeC,WAAW,sCAAwCF,EAAS,OAQ7F,IAAIG,IACFC,YAAa,IAAM,EAAG,KAAO,MAC7BC,aAAc,IAAM,KAAO,KAAO,GAClCC,eAAgB,KAAO,IAAM,IAAM,KACnCC,YAAa,IAAM,KAAO,IAAM,KAChCC,aAAc,IAAM,IAAM,IAAM,KAChCC,eAAgB,KAAO,IAAM,KAAO,MACpCC,aAAc,IAAM,KAAO,KAAO,KAClCC,cAAe,KAAO,IAAM,KAAO,GACnCC,gBAAiB,KAAO,KAAO,KAAO,GACtCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,KAAO,IAAM,IAAM,GAClCC,gBAAiB,IAAM,EAAG,KAAO,GACjCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,IAAM,EAAG,IAAM,GAC9BC,gBAAiB,IAAM,EAAG,IAAM,GAChCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,IAAM,EAAG,IAAM,GAC7BC,eAAgB,EAAG,EAAG,EAAG,GACzBC,YAAa,GAAK,IAAM,IAAM,MAC9BC,aAAc,KAAO,IAAM,KAAO,GAClCC,eAAgB,KAAO,KAAO,IAAM,KACpCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,KAAO,KAAO,IAAM,OAClCC,eAAgB,KAAO,IAAM,KAAO,MAGtCjV,GAAS4B,IAAI0Q,OAASmB,EAwCtBzT,EAAS4B,IAAIyO,KAAOrQ,EAASoM,MAAM3L,QACjCkM,YAAauG,KAGfhT,OAAQC,SAAUH,GASnB,SAASE,EAAQC,EAAUH,GAC1B,YAiDA,SAASgO,GAAY5K,GACnB,GACED,GADE+R,KAEF/Q,EAAiBnE,EAAS0C,mBAAmB1C,EAASkC,aAAanC,KAAKoC,MAAOpC,KAAKoC,KAAK8E,OAAO1E,OAGlGxC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAGhGhS,EAASnD,EAASkE,UAAUnE,KAAK2B,IAAKyC,EAAgBf,EAEtD,IAAI2D,GAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,GAE/C6D,EAASlH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW0N,YAC1DpO,EAAOjH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW2N,UAExDrV,GAAS8G,YAAYC,EAAWhH,KAAKoC,KAAM6E,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,uBAC1F1G,EAAS2I,YAAY5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAChD6S,EAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,KAG7B9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAMP,KAAK,GAJDuD,GAEFoK,EADAC,KAGO/S,EAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAC5C0I,EAAInL,EAAS6I,aAAa9B,EAAW5D,EAAQgB,EAAe9B,GAAII,GAChE+S,EAAgBrQ,KAAKgG,EAAExF,EAAGwF,EAAEtF,GAIxBzC,EAAQqS,YACVF,EAAQL,EAAa7S,GAAGwE,KAAK,QAC3BX,GAAIiF,EAAExF,EACNQ,GAAIgF,EAAEtF,EACNO,GAAI+E,EAAExF,EAAI,IACVU,GAAI8E,EAAEtF,GACLzC,EAAQsE,WAAW6N,OAAO1T,MAC3Bf,MAASqD,EAAe9B,GAAGI,IAC1BzC,EAASmP,MAAME,KAElBtP,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNhH,MAAOqD,EAAe9B,GAAGI,GACzB2E,MAAO3E,EACPuF,MAAOkN,EAAa7S,GACpB4F,QAASsN,EACT5P,EAAGwF,EAAExF,EACLE,EAAGsF,EAAEtF,IAMX,IAAIzC,EAAQsS,UAAYtS,EAAQuS,SAAU,CAExC,GAAIC,IAAgB,IAAMJ,EAAgB,GAAK,IAAMA,EAAgB,GAGrE,IAAIpS,EAAQyS,YAAcL,EAAgBjT,OAAS,EAGjD,IAAI,GADAuT,GAAK9V,EAAS8K,kBAAkB0K,GAC5BO,EAAI,EAAGA,EAAID,EAAGvT,OAAQwT,IAC5BH,EAAazQ,KAAK,IAAM2Q,EAAGC,GAAGnO,YAGhC,KAAI,GAAIoO,GAAI,EAAGA,EAAIR,EAAgBjT,OAAQyT,GAAK,EAC9CJ,EAAazQ,KAAK,IAAMqQ,EAAgBQ,EAAI,GAAK,IAAMR,EAAgBQ,GAI3E,IAAG5S,EAAQuS,SAAU,CAGnB,GAAIM,GAAWpT,KAAKW,IAAIX,KAAK0B,IAAInB,EAAQ6S,SAAU9S,EAAOK,KAAML,EAAOoB,KAGnE2R,EAAmBN,EAAa9I,QAGhCqJ,EAAoBnW,EAAS6I,aAAa9B,EAAW5D,GAAS8S,GAAW,EAE7EC,GAAiBxK,OAAO,EAAG,EAAG,IAAMyK,EAAkBxQ,EAAI,IAAMwQ,EAAkBtQ,GAClFqQ,EAAiB,GAAK,IAAMV,EAAgB,GAAK,IAAMA,EAAgB,GACvEU,EAAiB/Q,KAAK,IAAMqQ,EAAgBA,EAAgBjT,OAAS,GAAK,IAAM4T,EAAkBtQ,EAGlG,IAAIuQ,GAAOlB,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAGiL,EAAiBtO,KAAK,KACxBxE,EAAQsE,WAAW0O,MAAM,GAAMvU,MAChCqD,OAAUf,EAAe9B,IACxBrC,EAASmP,MAAME,IAElBtP,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,OACN5C,OAAQf,EAAe9B,GACvB+E,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASmO,IAIb,GAAGhT,EAAQsS,SAAU,CACnB,GAAIW,GAAOnB,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAG2K,EAAahO,KAAK,KACpBxE,EAAQsE,WAAW2O,MAAM,GAAMxU,MAChCqD,OAAUf,EAAe9B,IACxBrC,EAASmP,MAAME,IAElBtP,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,OACN5C,OAAQf,EAAe9B,GACvB+E,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASoO,MAMjBtW,KAAKmH,aAAaW,KAAK,WACrB1E,OAAQA,EACR4D,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAgJb,QAASkT,GAAKnV,EAAOgB,EAAMiB,EAAS4F,GAClChJ,EAASsW,KAAKrJ,MAAMN,YAAYI,KAAKhN,KACnCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GAhVJ,GAAID,IACFrF,OACEC,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,MAElC4E,OACErB,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,KAChC6E,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRkT,UAAU,EACVD,WAAW,EACXE,UAAU,EACVM,SAAU,EACVJ,YAAY,EACZ5R,IAAKzB,OACLsB,KAAMtB,OACNiB,aAAc,EACdiE,YACEyN,MAAO,gBACP7M,MAAO,WACP8M,WAAY,YACZ9S,OAAQ,YACR+T,KAAM,UACNd,MAAO,WACPa,KAAM,UACNpP,KAAM,UACNqO,UAAW,WACXzM,SAAU,cACVjB,WAAY,iBAyShB3H,GAASsW,KAAOtW,EAASsO,KAAK7N,QAC5BkM,YAAa2J,EACbtI,YAAaA,KAGf9N,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA2CA,SAASgO,GAAY5K,GACnB,GACED,GADE+R,KAEF/Q,EAAiBnE,EAAS0C,mBAAmB1C,EAASkC,aAAanC,KAAKoC,MAAOpC,KAAKoC,KAAK8E,OAAO1E,OAGlGxC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAGhGhS,EAASnD,EAASkE,UAAUnE,KAAK2B,IAAKyC,EAAgBf,EAAS,EAE/D,IAAI2D,GAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,GAE/C6D,EAASlH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW0N,YAC1DpO,EAAOjH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW2N,WAEtDkB,EAAYvW,EAAS6I,aAAa9B,EAAW5D,GAAS,GAAI,EAE5DnD,GAAS8G,YAAYC,EAAWhH,KAAKoC,KAAM6E,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,uBAC1F1G,EAAS2I,YAAY5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAEhD,GAAImU,GAAQnU,GAAKtC,KAAKoC,KAAKG,OAAOC,OAAS,GAAK,EAE9CkU,EAAkB1P,EAAUxF,QAAU4C,EAAe9B,GAAGE,OAAS,CAEnE2S,GAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,KAG7B9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAEP,KAAI,GAAInF,GAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAAK,CAChD,GACEiU,GADEvL,EAAInL,EAAS6I,aAAa9B,EAAW5D,EAAQgB,EAAe9B,GAAII,EAKpE0I,GAAExF,GAAK8Q,EAAmBD,EAAQpT,EAAQuT,kBAE1CD,EAAMxB,EAAa7S,GAAGwE,KAAK,QACzBX,GAAIiF,EAAExF,EACNQ,GAAIoQ,EAAU1Q,EACdO,GAAI+E,EAAExF,EACNU,GAAI8E,EAAEtF,GACLzC,EAAQsE,WAAWgP,KAAK7U,MACzBf,MAASqD,EAAe9B,GAAGI,IAC1BzC,EAASmP,MAAME,KAElBtP,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,MACNhH,MAAOqD,EAAe9B,GAAGI,GACzB2E,MAAO3E,EACPuF,MAAOkN,EAAa7S,GACpB4F,QAASyO,EACTxQ,GAAIiF,EAAExF,EACNQ,GAAIoQ,EAAU1Q,EACdO,GAAI+E,EAAExF,EACNU,GAAI8E,EAAEtF,KAKZ9F,KAAKmH,aAAaW,KAAK,WACrB1E,OAAQA,EACR4D,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAwGb,QAASwT,GAAIzV,EAAOgB,EAAMiB,EAAS4F,GACjChJ,EAAS4W,IAAI3J,MAAMN,YAAYI,KAAKhN,KAClCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GArOJ,GAAID,IACFrF,OACEC,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,MAElC4E,OACErB,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,KAChC6E,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRsB,KAAMtB,OACNyB,IAAKzB,OACLiB,aAAc,EACdkT,kBAAmB,GACnBjP,YACEyN,MAAO,eACP7M,MAAO,WACP8M,WAAY,YACZ9S,OAAQ,YACRoU,IAAK,SACL1P,KAAM,UACNqO,UAAW,WACXzM,SAAU,cACVjB,WAAY,iBAoMhB3H,GAAS4W,IAAM5W,EAASsO,KAAK7N,QAC3BkM,YAAaiK,EACb5I,YAAaA,KAGf9N,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAwBA,SAAS6W,GAAwBC,EAAQxO,EAAOyO,GAC9C,GAAIC,GAAa1O,EAAM3C,EAAImR,EAAOnR,CAElC,OAAGqR,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SAIX,QAAS/I,GAAY5K,GACnB,GACE2D,GACAxB,EACA0R,EACAC,EAJEhC,KAKFiC,EAAa/T,EAAQ+T,WACrBxU,EAAY3C,EAASkC,aAAanC,KAAKoC,KAGzCpC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAEhGpO,EAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,EAAS,EAAG,GAE3DmC,EAAS1C,KAAK0B,IAAIwC,EAAUxF,QAAU,EAAGwF,EAAUvF,SAAW,GAE9D0V,EAAe9T,EAAQgU,OAASzU,EAAU0U,OAAO,SAASC,EAAeC,GACvE,MAAOD,GAAgBC,GACtB,GAKHhS,GAAUnC,EAAQoU,MAAQpU,EAAQqU,WAAa,EAAK,EAIpDR,EAAc7T,EAAQoU,MAAQjS,EAASA,EAAS,EAEhD0R,GAAe7T,EAAQgF,WAevB,KAAK,GAZD0O,IACFnR,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAU,EACtCsE,EAAGkB,EAAUV,GAAKU,EAAUvF,SAAW,GAIrCkW,EAEU,IAFa3X,KAAKoC,KAAKG,OAAO+O,OAAO,SAASsG,GAC1D,MAAe,KAARA,IACNpV,OAIMF,EAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAChD6S,EAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,IAAK,KAAM,MAAM,GAG9C9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAEP,IAAIgQ,GAAWT,EAAaxU,EAAUN,GAAK6U,EAAe,GAGvDU,GAAWT,IAAe,MAC3BS,GAAY,IAGd,IAAIC,GAAQ7X,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGN,EAAQ4R,GAAoB,IAAN9U,GAAWqV,EAAuB,EAAI,KACpHI,EAAM9X,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGN,EAAQqS,GAC5DG,EAAoC,KAAzBH,EAAWT,EAAoB,IAAM,IAChDlM,GAEE,IAAK6M,EAAInS,EAAGmS,EAAIjS,EAEhB,IAAKN,EAAQA,EAAQ,EAAGwS,EAAU,EAAGF,EAAMlS,EAAGkS,EAAMhS,EAIrDzC,GAAQoU,SAAU,GACnBvM,EAAE9F,KAAK,IAAK2R,EAAOnR,EAAGmR,EAAOjR,EAK/B,IAAImS,GAAO9C,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAGA,EAAErD,KAAK,MACTxE,EAAQsE,WAAWoF,OAAS1J,EAAQoU,MAAQ,IAAMpU,EAAQsE,WAAW8P,MAAQ,IA6BhF,IA1BAQ,EAAKnW,MACHf,MAAS6B,EAAUN,IAClBrC,EAASmP,MAAME,KAGfjM,EAAQoU,SAAU,GACnBQ,EAAKnW,MACHE,MAAS,mBAAqBqB,EAAQqU,WAAc,OAKxD1X,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNhH,MAAO6B,EAAUN,GACjB6U,aAAcA,EACd9P,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAAS+P,EACTlB,OAAQA,EACRvR,OAAQA,EACR4R,WAAYA,EACZS,SAAUA,IAITxU,EAAQ8E,UAAW,CAEpB,GAAIC,GAAgBnI,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGoR,EAAaE,GAAcS,EAAWT,GAAc,GACpH9P,EAAoBjE,EAAQkE,sBAAsBvH,KAAKoC,KAAK8E,OAASlH,KAAKoC,KAAK8E,OAAO5E,GAAKM,EAAUN,GAAIA,GAEvGgG,EAAe6M,EAAa7S,GAAGwE,KAAK,QACtCoR,GAAI9P,EAAcxC,EAClBuS,GAAI/P,EAActC,EAClBsS,cAAetB,EAAwBC,EAAQ3O,EAAe/E,EAAQgV,iBACrEhV,EAAQsE,WAAWY,OAAO9B,KAAK,GAAKa,EAGvCtH,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNV,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,IAMrBsR,EAAaS,EAGf7X,KAAKmH,aAAaW,KAAK,WACrBd,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAoFb,QAASiV,GAAIlX,EAAOgB,EAAMiB,EAAS4F,GACjChJ,EAASqY,IAAIpL,MAAMN,YAAYI,KAAKhN,KAClCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GA/QJ,GAAID,IACFxH,MAAOiB,OACPhB,OAAQgB,OACRiB,aAAc,EACdiE,YACEyN,MAAO,eACP7S,OAAQ,YACRwK,MAAO,WACP0K,MAAO,WACPlP,MAAO,YAET6O,WAAY,EACZC,MAAO5U,OACPgV,OAAO,EACPC,WAAY,GACZvP,WAAW,EACXE,YAAa,EACbd,sBAAuBtH,EAASI,KAChCkY,eAAe,EACfF,eAAgB,UAgQlBpY,GAASqY,IAAMrY,EAASsO,KAAK7N,QAC3BkM,YAAa0L,EACbrK,YAAaA,EACb6I,wBAAyBA,KAG3B3W,OAAQC,SAAUH,GAGbA","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.4.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.3.1';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas\n /**\n * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property\n * where deltas for specific object properties can be found for the given object nesting level. For nested objects the\n * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also\n * contain a __delta__ property with the deltas of their level.\n *\n * @param {Object|Array} a Object that should be used to analyzed delta to object b\n * @param {Object|Array} b The second object where the deltas from a should be analyzed\n * @returns {Object} Delta descriptor object or null\n */\n Chartist.deltaDescriptor = function(a, b) {\n var summary = {\n added: 0,\n removed: 0,\n modified: 0\n };\n\n function findDeltasRecursively(a, b) {\n var descriptor = {\n __delta__: {}\n };\n\n // First check for removed and modified properties\n Object.keys(a).forEach(function(property) {\n if(!b.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'remove',\n property: property,\n ours: a[property]\n };\n summary.removed++;\n } else {\n if(typeof a[property] === 'object') {\n var subDescriptor = findDeltasRecursively(a[property], b[property]);\n if(subDescriptor) {\n descriptor[property] = subDescriptor;\n }\n } else {\n if(a[property] !== b[property]) {\n descriptor.__delta__[property] = {\n type: 'modify',\n property: property,\n ours: a[property],\n theirs: b[property]\n };\n summary.modified++;\n }\n }\n }\n });\n\n // Check for added properties\n Object.keys(b).forEach(function(property) {\n if(!a.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'added',\n property: property,\n theirs: b[property]\n };\n summary.added++;\n }\n });\n\n return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null;\n }\n\n var delta = findDeltasRecursively(a, b);\n if(delta) {\n delta.__delta__.summary = summary;\n }\n\n return delta;\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index 9d3a3f7e..f7e6d6fc 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.4.0", + "version": "0.4.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From e92553af66c690229f8454d164ab106f48ff13bc Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Nov 2014 00:54:40 +0100 Subject: [PATCH 087/593] Fixed table width problems in documentation site --- source/site/data/pages/index.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/source/site/data/pages/index.yml b/source/site/data/pages/index.yml index fedce55c..8d4c6e72 100644 --- a/source/site/data/pages/index.yml +++ b/source/site/data/pages/index.yml @@ -215,24 +215,19 @@ sections: header: - Project - Type - - Website rows: - - - ng-chartist.js + - 'ng-chartist.js' - Angular Directive - - 'https://github.com/paradox41/ng-chartist.js' - - - react-chartist + - 'react-chartist' - React Component - - 'https://fraserxu.me/react-chartist' - - - meteor-chartist-js + - 'meteor-chartist-js' - Meteor Package - - 'https://github.com/mfpierre/meteor-chartist-js' - - - tablepress_chartist + - 'tablepress_chartist' - Wordpress / Tablepress Extension - - 'https://github.com/soderlind/tablepress_chartist' - title: Chart CSS animation example level: 3 items: From 56bee2d9d66d6d9a436d97274b35d5b33e924d9c Mon Sep 17 00:00:00 2001 From: Autarc Date: Fri, 21 Nov 2014 12:09:34 +0100 Subject: [PATCH 088/593] Update build dependencies --- package.json | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index f7e6d6fc..16314b77 100644 --- a/package.json +++ b/package.json @@ -35,36 +35,33 @@ ], "dependencies": {}, "devDependencies": { - "grunt": "~0.4.1", - "grunt-autoprefixer": "~0.4.0", - "grunt-concurrent": "~0.4.1", - "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-coffee": "~0.7.0", - "grunt-sass": "~0.14.2", - "grunt-contrib-concat": "~0.3.0", + "assemble": "~0.4.36", + "grunt": "^0.4.5", + "grunt-concurrent": "^1.0.0", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-concat": "^0.5.0", "grunt-contrib-connect": "~0.5.0", - "grunt-contrib-copy": "~0.4.1", - "grunt-contrib-cssmin": "~0.9.0", + "grunt-contrib-copy": "^0.7.0", + "grunt-contrib-cssmin": "^0.10.0", "grunt-contrib-htmlmin": "~0.1.3", "grunt-contrib-imagemin": "~0.3.0", + "grunt-contrib-jasmine": "~0.7.0", "grunt-contrib-jshint": "~0.7.1", - "grunt-contrib-uglify": "~0.4.0", - "grunt-contrib-watch": "~0.5.2", - "grunt-newer": "~0.5.4", + "grunt-contrib-uglify": "^0.6.0", + "grunt-contrib-watch": "^0.6.1", + "grunt-critical": "0.0.3", + "grunt-doxication": "0.0.4", + "grunt-newer": "^0.8.0", + "grunt-sass": "^0.16.1", "grunt-svgmin": "~0.2.0", + "grunt-umd": "^2.0.1", "grunt-usemin": "~2.3.0", - "jshint-stylish": "~0.1.3", - "load-grunt-tasks": "~0.2.0", - "time-grunt": "~0.2.1", - "grunt-contrib-jasmine": "~0.7.0", - "jasmine-fixture": "~1.0.8", - "assemble": "~0.4.36", "handlebars-helpers": "~0.5.5", - "seed-random": "~2.2.0", - "grunt-umd": "^1.7.4", - "grunt-doxication": "0.0.4", + "jasmine-fixture": "~1.0.8", + "jshint-stylish": "~0.1.3", "lodash": "^2.4.1", - "grunt-critical": "0.0.3" + "seed-random": "~2.2.0", + "time-grunt": "^1.0.0" }, "engines": { "node": ">=0.8.0" From f0ab33c6258310733e5a7aca51545b7de5e6c251 Mon Sep 17 00:00:00 2001 From: Autarc Date: Fri, 21 Nov 2014 12:12:18 +0100 Subject: [PATCH 089/593] Refactored build tasks --- Gruntfile.js | 504 +++-------------------------------------- package.json | 1 + tasks/aliases.yml | 37 +++ tasks/assemble.js | 29 +++ tasks/clean.js | 28 +++ tasks/concat.js | 33 +++ tasks/concurrent.js | 26 +++ tasks/connect.js | 45 ++++ tasks/copy.js | 65 ++++++ tasks/critical.js | 25 ++ tasks/cssmin.js | 23 ++ tasks/doxication.js | 22 ++ tasks/htmlmin.js | 31 +++ tasks/imagemin.js | 25 ++ tasks/jasmine.js | 34 +++ tasks/jshint.js | 29 +++ tasks/sass.js | 47 ++++ tasks/svgmin.js | 32 +++ tasks/uglify.js | 25 ++ tasks/umd.js | 21 ++ tasks/usemin.js | 34 +++ tasks/useminPrepare.js | 21 ++ tasks/watch.js | 51 +++++ 23 files changed, 712 insertions(+), 476 deletions(-) create mode 100644 tasks/aliases.yml create mode 100644 tasks/assemble.js create mode 100644 tasks/clean.js create mode 100644 tasks/concat.js create mode 100644 tasks/concurrent.js create mode 100644 tasks/connect.js create mode 100644 tasks/copy.js create mode 100644 tasks/critical.js create mode 100644 tasks/cssmin.js create mode 100644 tasks/doxication.js create mode 100644 tasks/htmlmin.js create mode 100644 tasks/imagemin.js create mode 100644 tasks/jasmine.js create mode 100644 tasks/jshint.js create mode 100644 tasks/sass.js create mode 100644 tasks/svgmin.js create mode 100644 tasks/uglify.js create mode 100644 tasks/umd.js create mode 100644 tasks/usemin.js create mode 100644 tasks/useminPrepare.js create mode 100644 tasks/watch.js diff --git a/Gruntfile.js b/Gruntfile.js index b479eb75..da71508e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,452 +1,45 @@ +/** + * Grunt Configurations + * ==================== + * + * Seperate tasks and configurations are declared in '/tasks'. + * + * Link: https://github.com/firstandthird/load-grunt-config + */ + 'use strict'; module.exports = function (grunt) { - // Load grunt tasks automatically - require('load-grunt-tasks')(grunt); - - // Time how long tasks take. Can help when optimizing build times + // tracks how long a tasks take require('time-grunt')(grunt); - var pkg = require('./package.json'); - - grunt.loadNpmTasks('assemble'); - - // Define the configuration for all the tasks - grunt.initConfig({ - - // Grunt package with settings - pkg: grunt.file.readJSON('package.json'), - year: new Date().getFullYear(), - - // Watches files for changes and runs tasks based on the changed files - watch: { - assemble: { - files: ['<%= pkg.config.source %>/site/**/*.{hbs,yml,json,js}'], - tasks: ['doxication', 'assemble'] - }, - doxication: { - files: ['.tmp/data/**/*.{yml,json}'], - tasks: ['doxication', 'assemble'] - }, - js: { - files: ['<%= pkg.config.source %>/scripts/{,*/}*.js'], - tasks: ['newer:jshint:all'], - options: { - livereload: true - } - }, - jsTest: { - files: ['test/spec/{,*/}*.js'], - tasks: ['newer:jshint:test', 'jasmine'] - }, - sass: { - files: ['<%= pkg.config.source %>/styles/**/*.{scss,sass}'], - tasks: ['sass:server'] - }, - gruntfile: { - files: ['Gruntfile.js'] - }, - livereload: { - options: { - livereload: '<%= connect.options.livereload %>' - }, - files: [ - '.tmp/{,*/}*.html', - '.tmp/styles/{,*/}*.css', - '<%= pkg.config.source %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' - ] - } - }, - - // The actual grunt server settings - connect: { - options: { - port: 9000, - // Change this to '0.0.0.0' to access the server from outside. - hostname: '0.0.0.0', - livereload: 35729 - }, - livereload: { - options: { - open: true, - base: [ - '.tmp', - '<%= pkg.config.source %>' - ] - } - }, - test: { - options: { - port: 9001, - base: [ - '.tmp', - 'test', - '<%= pkg.config.source %>' - ] - } - }, - dist: { - options: { - base: '<%= pkg.config.dist %>' - } - } - }, - - // Make sure code styles are up to par and there are no obvious mistakes - jshint: { - options: { - jshintrc: '.jshintrc', - reporter: require('jshint-stylish') - }, - all: [ - 'Gruntfile.js', - '<%= pkg.config.source %>/scripts/{,*/}*.js' - ], - test: { - options: { - jshintrc: 'test/.jshintrc' - }, - src: ['test/spec/{,*/}*.js'] - } - }, - - // Empties folders to start fresh - clean: { - dist: { - files: [ - { - dot: true, - src: [ - '.tmp', - '<%= pkg.config.dist %>/*', - '!<%= pkg.config.dist %>/.git*' - ] - } - ] - }, - server: '.tmp' - }, - - assemble: { - options: { - helpers: ['<%= pkg.config.source %>/site/helpers/**/*.js'], - partials: ['<%= pkg.config.source %>/site/partials/**/*.hbs'], - layoutdir: '<%= pkg.config.source %>/site/layouts', - layoutext: '.hbs', - layout: ['default'], - data: ['<%= pkg.config.source %>/site/data/**/*.{json,yml}', '.tmp/data/**/*.{json,yml}'] - }, - pages: { - expand: true, - cwd: '<%= pkg.config.source %>/site', - src: ['*.hbs'], - dest: '.tmp' - } - }, - - // Compile SASS into CSS with libsass (node-sass) - sass: { - options: { - includePaths: ['<%= pkg.config.source %>/bower_components'], - imagePath: '<%= pkg.config.source %>/images' - }, - dist: { - options: { - sourceMap: false - }, - files: [ - { - expand: true, - cwd: '<%= pkg.config.source %>/styles', - src: '{,*/}*.{scss,sass}', - ext: '.css', - dest: '.tmp/styles' - } - ] - }, - server: { - options: { - sourceMap: true - }, - files: [ - { - expand: true, - cwd: '<%= pkg.config.source %>/styles', - src: '{,*/}*.{scss,sass}', - ext: '.css', - dest: '.tmp/styles' - } - ] - } - }, - - - // Reads HTML for usemin blocks to enable smart builds that automatically - // concat, minify and revision files. Creates configurations in memory so - // additional tasks can operate on them - useminPrepare: { - html: '.tmp/index.html', - options: { - dest: '<%= pkg.config.dist %>' - } + // load task and configurations + require('load-grunt-config')(grunt, { + configPath: __dirname + '/tasks', + data: { + pkg: grunt.file.readJSON('package.json'), + year: new Date().getFullYear() }, - - // Performs rewrites based on rev and the useminPrepare configuration - usemin: { - html: ['<%= pkg.config.dist %>/{,*/}*.html'], - css: ['<%= pkg.config.dist %>/styles/{,*/}*.css'], - options: { - assetsDirs: ['<%= pkg.config.dist %>'], - blockReplacements: { - js: function (block) { - - var asyncScripts = [ - 'scripts/all.js' - ]; - - var isAsync = block.async || asyncScripts.indexOf(block.dest) > -1; - - return isAsync ? - ' + + diff --git a/source/site/data/pages/examples.yml b/site/templates/data/pages/examples.yml similarity index 100% rename from source/site/data/pages/examples.yml rename to site/templates/data/pages/examples.yml diff --git a/source/site/data/pages/getting-started.yml b/site/templates/data/pages/getting-started.yml similarity index 99% rename from source/site/data/pages/getting-started.yml rename to site/templates/data/pages/getting-started.yml index bd0d660e..6ac17178 100644 --- a/source/site/data/pages/getting-started.yml +++ b/site/templates/data/pages/getting-started.yml @@ -126,7 +126,7 @@ sections: data: id: default-Sass-settings button: Show default settings - path: source/styles/settings/_chartist-settings.scss + path: site/styles/settings/_chartist-settings.scss lang: scss - title: Create your first chart diff --git a/source/site/data/pages/index.yml b/site/templates/data/pages/index.yml similarity index 98% rename from source/site/data/pages/index.yml rename to site/templates/data/pages/index.yml index 8d4c6e72..9617e3bd 100644 --- a/source/site/data/pages/index.yml +++ b/site/templates/data/pages/index.yml @@ -208,7 +208,7 @@ sections: items: - type: text data: - text: These projects and wrapper libraries are known to me right now that either use Chartist.js or wrap them into a library for usage in a framework. If you know other projects that use Chartist.js please let us know or make a pull request for this file. + text: These projects and wrapper libraries are known to me right now that either use Chartist.js or wrap them into a library for usage in a framework. If you know other projects that use Chartist.js please let us know or make a pull request for this file. - type: table data: id: chartist-projects-table diff --git a/source/site/examples.hbs b/site/templates/examples.hbs similarity index 100% rename from source/site/examples.hbs rename to site/templates/examples.hbs diff --git a/site/templates/examples/behavior-with-jquery.js b/site/templates/examples/behavior-with-jquery.js new file mode 100644 index 00000000..a79cafcb --- /dev/null +++ b/site/templates/examples/behavior-with-jquery.js @@ -0,0 +1,47 @@ +new Chartist.Line('.ct-chart', { + labels: ['1', '2', '3', '4', '5', '6'], + series: [ + { + name: 'Fibonacci sequence', + data: [1, 2, 3, 5, 8, 13] + }, + { + name: 'Golden section', + data: [1, 1.618, 2.618, 4.236, 6.854, 11.09] + } + ] +}); + +var easeOutQuad = function (x, t, b, c, d) { + return -c * (t /= d) * (t - 2) + b; +}; + +var $chart = $('.ct-chart'); + +var $toolTip = $chart + .append('
    ') + .find('.tooltip') + .hide(); + +$chart.on('mouseenter', '.ct-point', function() { + var $point = $(this), + value = $point.attr('ct:value'), + seriesName = $point.parent().attr('ct:series-name'); + + $point.animate({'stroke-width': '50px'}, 300, easeOutQuad); + $toolTip.html(seriesName + '
    ' + value).show(); +}); + +$chart.on('mouseleave', '.ct-point', function() { + var $point = $(this); + + $point.animate({'stroke-width': '20px'}, 300, easeOutQuad); + $toolTip.hide(); +}); + +$chart.on('mousemove', function(event) { + $toolTip.css({ + left: event.offsetX - $toolTip.width() / 2 - 10, + top: event.offsetY - $toolTip.height() - 40 + }); +}); \ No newline at end of file diff --git a/site/templates/examples/bi-polar-bar-interpolated.js b/site/templates/examples/bi-polar-bar-interpolated.js new file mode 100644 index 00000000..e9c1da8e --- /dev/null +++ b/site/templates/examples/bi-polar-bar-interpolated.js @@ -0,0 +1,18 @@ +var data = { + labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'], + series: [ + [1, 2, 4, 8, 6, -2, -1, -4, -6, -2] + ] +}; + +var options = { + high: 10, + low: -10, + axisX: { + labelInterpolationFnc: function(value, index) { + return index % 2 === 0 ? value : null; + } + } +}; + +new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file diff --git a/site/templates/examples/example-bar-with-circle-modify-drawing.js b/site/templates/examples/example-bar-with-circle-modify-drawing.js new file mode 100644 index 00000000..a5b71c4b --- /dev/null +++ b/site/templates/examples/example-bar-with-circle-modify-drawing.js @@ -0,0 +1,28 @@ +// Create a simple bi-polar bar chart +var chart = new Chartist.Bar('.ct-chart', { + labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'], + series: [ + [1, 2, 4, 8, 6, -2, -1, -4, -6, -2] + ] +}, { + high: 10, + low: -10, + axisX: { + labelInterpolationFnc: function(value, index) { + return index % 2 === 0 ? value : null; + } + } +}); + +// Listen for draw events on the bar chart +chart.on('draw', function(data) { + // If this draw event is of type bar we can use the data to create additional content + if(data.type === 'bar') { + // We use the group element of the current series to append a simple circle with the bar peek coordinates and a circle radius that is depending on the value + data.group.append(new Chartist.Svg('circle', { + cx: data.x2, + cy: data.y2, + r: Math.abs(data.value) * 2 + 5 + }, 'ct-slice')); + } +}); diff --git a/site/templates/examples/example-bipolar-line-area.js b/site/templates/examples/example-bipolar-line-area.js new file mode 100644 index 00000000..03cd06fc --- /dev/null +++ b/site/templates/examples/example-bipolar-line-area.js @@ -0,0 +1,19 @@ +new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8], + series: [ + [1, 2, 3, 1, -2, 0, 1, 0], + [-2, -1, -2, -1, -2.5, -1, -2, -1], + [0, 0, 0, 1, 2, 2.5, 2, 1], + [2.5, 2, 1, 0.5, 1, 0.5, -1, -2.5] + ] +}, { + high: 3, + low: -3, + showArea: true, + showLine: false, + showPoint: false, + axisX: { + showLabel: false, + showGrid: false + } +}); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-four.js b/site/templates/examples/example-gallery-four.js new file mode 100644 index 00000000..f2a5f704 --- /dev/null +++ b/site/templates/examples/example-gallery-four.js @@ -0,0 +1,33 @@ +var data = { + series: [60, 20] +}; + +var options = { + donut: true, + donutWidth: 40, + total: 100, + labelInterpolationFnc: function(value) { + return value + '%'; + } +}; + +var responsiveOptions = [ + [ + Foundation.media_queries.medium, + { + labelOffset: 30, + chartPadding: 10, + labelDirection: 'explode' + } + ], + [ + Foundation.media_queries.large, + { + labelOffset: -30, + chartPadding: 0, + labelDirection: 'implode' + } + ] +]; + +new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-one.js b/site/templates/examples/example-gallery-one.js new file mode 100644 index 00000000..daeb09ea --- /dev/null +++ b/site/templates/examples/example-gallery-one.js @@ -0,0 +1,11 @@ +var data = { + labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9'], + series: [ + [12, 9, 7, 8, 6, 4, 3, 2, 0], + [2, 1, 3.5, 7, 9, 8, 7.7, 4, 7], + [1, 3, 4, 5, 6, 8, 9, 10, 11], + [11, 7.5, 5.5, 5.5, 4, 3.5, 2, 1, 0] + ] +}; + +new Chartist.Line('.ct-chart', data); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-three.js b/site/templates/examples/example-gallery-three.js new file mode 100644 index 00000000..631f693f --- /dev/null +++ b/site/templates/examples/example-gallery-three.js @@ -0,0 +1,40 @@ +var data = { + labels: ['Day one', 'Day two', 'Day three', 'Day four'], + series: [20, 15, 40, 10] +}; + +var options = { + labelInterpolationFnc: function(value) { + return value.split(/\s+/).reduce(function(str, elem) { + return str + elem[0] + '.'; + }, ''); + } +}; + +var responsiveOptions = [ + [ + Foundation.media_queries.medium, + { + chartPadding: 30, + labelOffset: 50, + labelDirection: 'explode', + labelInterpolationFnc: function(value) { + return value; + } + } + ], + [ + Foundation.media_queries.large, + { + labelOffset: 80 + } + ], + [ + Foundation.media_queries.xlarge, + { + labelOffset: 100 + } + ] +]; + +new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-two.js b/site/templates/examples/example-gallery-two.js new file mode 100644 index 00000000..e408db59 --- /dev/null +++ b/site/templates/examples/example-gallery-two.js @@ -0,0 +1,13 @@ +var data = { + labels: ['1938', '1939', '1940', '1941', '1942', '1943'], + series: [ + [12000, 9000, 7000, 8000, 12000, 10000], + [2000, 1000, 3500, 7000, 5000, 9000] + ] +}; + +var options = { + seriesBarDistance: 5 +}; + +new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file diff --git a/site/templates/examples/example-line-area.js b/site/templates/examples/example-line-area.js new file mode 100644 index 00000000..ab86b923 --- /dev/null +++ b/site/templates/examples/example-line-area.js @@ -0,0 +1,9 @@ +new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8], + series: [ + [5, 9, 7, 8, 5, 3, 5, 4] + ] +}, { + low: 0, + showArea: true +}); \ No newline at end of file diff --git a/site/templates/examples/example-line-modify-drawing.js b/site/templates/examples/example-line-modify-drawing.js new file mode 100644 index 00000000..32785ab1 --- /dev/null +++ b/site/templates/examples/example-line-modify-drawing.js @@ -0,0 +1,30 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5], + series: [ + [12, 9, 7, 8, 5] + ] +}); + +// Listening for draw events that get emitted by the Chartist chart +chart.on('draw', function(data) { + // If the draw event was triggered from drawing a point on the line chart + if(data.type === 'point') { + // We are creating a new path SVG element that draws a triangle around the point coordinates + var triangle = new Chartist.Svg('path', { + d: ['M', + data.x, + data.y - 15, + 'L', + data.x - 15, + data.y + 8, + 'L', + data.x + 15, + data.y + 8, + 'z'].join(' '), + style: 'fill-opacity: 1' + }, 'ct-area'); + + // With data.element we get the Chartist SVG wrapper and we can replace the original point drawn by Chartist with our newly created triangle + data.element.replace(triangle); + } +}); diff --git a/site/templates/examples/example-line-months-interpolation.js b/site/templates/examples/example-line-months-interpolation.js new file mode 100644 index 00000000..3c053bd6 --- /dev/null +++ b/site/templates/examples/example-line-months-interpolation.js @@ -0,0 +1,28 @@ +var data = { + labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + series: [ + [1, 2, 2.7, 0, 3, 5, 3, 4, 8, 10, 12, 7], + [0, 1.2, 2, 7, 2.5, 9, 5, 8, 9, 11, 14, 4], + [10, 9, 8, 6.5, 6.8, 6, 5.4, 5.3, 4.5, 4.4, 3, 2.8] + ] +}; + +var responsiveOptions = [ + [ + Foundation.media_queries.small, + { + axisX: { + labelInterpolationFnc: function (value, index) { + // Interpolation function causes only every 2nd label to be displayed + if (index % 2 !== 0) { + return false; + } else { + return value; + } + } + } + } + ] +]; + +new Chartist.Line('.ct-chart', data, null, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-line-simple-responsive.js b/site/templates/examples/example-line-simple-responsive.js new file mode 100644 index 00000000..62f98744 --- /dev/null +++ b/site/templates/examples/example-line-simple-responsive.js @@ -0,0 +1,41 @@ +/* Add a basic data series with six labels and values */ +var data = { + labels: ['1', '2', '3', '4', '5', '6'], + series: [ + { + data: [1, 2, 3, 5, 8, 13] + } + ] +}; + +/* Set some base options (settings will override the default settings in Chartist.js *see default settings*). We are adding a basic label interpolation function for the xAxis labels. */ +var options = { + axisX: { + labelInterpolationFnc: function(value) { + return 'Calendar Week ' + value; + } + } +}; + +/* Now we can specify multiple responsive settings that will override the base settings based on order and if the media queries match. In this example we are changing the visibility of dots and lines as well as use different label interpolations for space reasons. */ +var responsiveOptions = [ + ['screen and (min-width: 641px) and (max-width: 1024px)', { + showPoint: false, + axisX: { + labelInterpolationFnc: function(value) { + return 'Week ' + value; + } + } + }], + ['screen and (max-width: 640px)', { + showLine: false, + axisX: { + labelInterpolationFnc: function(value) { + return 'W' + value; + } + } + }] +]; + +/* Initialize the chart with the above settings */ +new Chartist.Line('#my-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-line-svg-animation.js b/site/templates/examples/example-line-svg-animation.js new file mode 100644 index 00000000..0e344de6 --- /dev/null +++ b/site/templates/examples/example-line-svg-animation.js @@ -0,0 +1,127 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], + series: [ + [12, 9, 7, 8, 5, 4, 6, 2, 3, 3, 4, 6], + [4, 5, 3, 7, 3, 5, 5, 3, 4, 4, 5, 5], + [5, 3, 4, 5, 6, 3, 3, 4, 5, 6, 3, 4], + [3, 4, 5, 6, 7, 6, 4, 5, 6, 7, 6, 3] + ] +}, { + low: 0 +}); + +// Let's put a sequence number aside so we can use it in the event callbacks +var seq = 0, + delays = 80, + durations = 500; + +// Once the chart is fully created we reset the sequence +chart.on('created', function() { + seq = 0; +}); + +// On each drawn element by Chartist we use the Chartist.Svg API to trigger SMIL animations +chart.on('draw', function(data) { + seq++; + + if(data.type === 'line') { + // If the drawn element is a line we do a simple opacity fade in. This could also be achieved using CSS3 animations. + data.element.animate({ + opacity: { + // The delay when we like to start the animation + begin: seq * delays + 1000, + // Duration of the animation + dur: durations, + // The value where the animation should start + from: 0, + // The value where it should end + to: 1 + } + }); + } else if(data.type === 'label' && data.axis === 'x') { + data.element.animate({ + y: { + begin: seq * delays, + dur: durations, + from: data.y + 100, + to: data.y, + // We can specify an easing function from Chartist.Svg.Easing + easing: 'easeInOutBack' + } + }); + } else if(data.type === 'label' && data.axis === 'y') { + data.element.animate({ + x: { + begin: seq * delays, + dur: durations, + from: data.x - 100, + to: data.x, + easing: 'easeInOutBack' + } + }); + } else if(data.type === 'point') { + data.element.animate({ + x1: { + begin: seq * delays, + dur: durations, + from: data.x - 10, + to: data.x, + easing: 'easeOutQuart' + }, + x2: { + begin: seq * delays, + dur: durations, + from: data.x - 10, + to: data.x, + easing: 'easeOutQuart' + }, + opacity: { + begin: seq * delays, + dur: durations, + from: 0, + to: 1, + easing: 'easeOutQuart' + } + }); + } else if(data.type === 'grid') { + // Using data.axis we get x or y which we can use to construct our animation definition objects + var pos1Animation = { + begin: seq * delays, + dur: durations, + from: data[data.axis + '1'] - 30, + to: data[data.axis + '1'], + easing: 'easeOutQuart' + }; + + var pos2Animation = { + begin: seq * delays, + dur: durations, + from: data[data.axis + '2'] - 100, + to: data[data.axis + '2'], + easing: 'easeOutQuart' + }; + + var animations = {}; + animations[data.axis + '1'] = pos1Animation; + animations[data.axis + '2'] = pos2Animation; + animations['opacity'] = { + begin: seq * delays, + dur: durations, + from: 0, + to: 1, + easing: 'easeOutQuart' + }; + + data.element.animate(animations); + } +}); + +// For the sake of the example we update the chart every time it's created with a delay of 10 seconds +chart.on('created', function() { + if(window.__exampleAnimateTimeout) { + clearTimeout(window.__exampleAnimateTimeout); + window.__exampleAnimateTimeout = null; + } + window.__exampleAnimateTimeout = setTimeout(chart.update.bind(chart), 12000); +}); + diff --git a/site/templates/examples/example-multiline-bar.js b/site/templates/examples/example-multiline-bar.js new file mode 100644 index 00000000..e71f1642 --- /dev/null +++ b/site/templates/examples/example-multiline-bar.js @@ -0,0 +1,20 @@ +new Chartist.Bar('.ct-chart', { + labels: ['First quarter of the year', 'Second quarter of the year', 'Third quarter of the year', 'Fourth quarter of the year'], + series: [ + [60000, 40000, 80000, 70000], + [40000, 30000, 70000, 65000], + [8000, 3000, 10000, 6000] + ] +}, { + seriesBarDistance: 10, + axisX: { + offset: 60 + }, + axisY: { + offset: 80, + labelInterpolationFnc: function(value) { + return value + ' CHF' + }, + scaleMinSpace: 15 + } +}); \ No newline at end of file diff --git a/site/templates/examples/example-simple-bar.js b/site/templates/examples/example-simple-bar.js new file mode 100644 index 00000000..f655562c --- /dev/null +++ b/site/templates/examples/example-simple-bar.js @@ -0,0 +1,32 @@ +var data = { + labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + series: [ + [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8], + [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4] + ] +}; + +var options = { + seriesBarDistance: 15 +}; + +var responsiveOptions = [ + ['screen and (min-width: 641px) and (max-width: 1024px)', { + seriesBarDistance: 10, + axisX: { + labelInterpolationFnc: function (value) { + return value; + } + } + }], + ['screen and (max-width: 640px)', { + seriesBarDistance: 5, + axisX: { + labelInterpolationFnc: function (value) { + return value[0]; + } + } + }] +]; + +new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-simple-svg-animation.js b/site/templates/examples/example-simple-svg-animation.js new file mode 100644 index 00000000..69a57816 --- /dev/null +++ b/site/templates/examples/example-simple-svg-animation.js @@ -0,0 +1,63 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], + series: [ + [12, 4, 2, 8, 5, 4, 6, 2, 3, 3, 4, 6], + [4, 8, 9, 3, 7, 2, 10, 5, 8, 1, 7, 10] + ] +}, { + low: 0, + showLine: false, + axisX: { + showLabel: false, + offset: 0 + }, + axisY: { + showLabel: false, + offset: 0 + } +}); + +// Let's put a sequence number aside so we can use it in the event callbacks +var seq = 0; + +// Once the chart is fully created we reset the sequence +chart.on('created', function() { + seq = 0; +}); + +// On each drawn element by Chartist we use the Chartist.Svg API to trigger SMIL animations +chart.on('draw', function(data) { + if(data.type === 'point') { + // If the drawn element is a line we do a simple opacity fade in. This could also be achieved using CSS3 animations. + data.element.animate({ + opacity: { + // The delay when we like to start the animation + begin: seq++ * 80, + // Duration of the animation + dur: 500, + // The value where the animation should start + from: 0, + // The value where it should end + to: 1 + }, + x1: { + begin: seq++ * 80, + dur: 500, + from: data.x - 100, + to: data.x, + // You can specify an easing function name or use easing functions from Chartist.Svg.Easing directly + easing: Chartist.Svg.Easing.easeOutQuart + } + }); + } +}); + +// For the sake of the example we update the chart every time it's created with a delay of 8 seconds +chart.on('created', function() { + if(window.__exampleAnimateTimeout) { + clearTimeout(window.__exampleAnimateTimeout); + window.__exampleAnimateTimeout = null; + } + window.__exampleAnimateTimeout = setTimeout(chart.update.bind(chart), 8000); +}); + diff --git a/site/templates/examples/line-scatter-random.js b/site/templates/examples/line-scatter-random.js new file mode 100644 index 00000000..593f37e9 --- /dev/null +++ b/site/templates/examples/line-scatter-random.js @@ -0,0 +1,36 @@ +var times = function(n) { + return Array.apply(null, new Array(n)); +}; + +var data = times(52).map(Math.random).reduce(function(data, rnd, index) { + data.labels.push(index + 1); + data.series.forEach(function(series) { + series.push(Math.random() * 100) + }); + + return data; +}, { + labels: [], + series: times(4).map(function() { return new Array() }) +}); + +var options = { + showLine: false, + axisX: { + labelInterpolationFnc: function(value, index) { + return index % 13 === 0 ? 'W' + value : null; + } + } +}; + +var responsiveOptions = [ + ['screen and (min-width: 640px)', { + axisX: { + labelInterpolationFnc: function(value, index) { + return index % 4 === 0 ? 'W' + value : null; + } + } + }] +]; + +new Chartist.Line('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/overlapping-bars.js b/site/templates/examples/overlapping-bars.js new file mode 100644 index 00000000..a8f16db1 --- /dev/null +++ b/site/templates/examples/overlapping-bars.js @@ -0,0 +1,24 @@ +var data = { + labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + series: [ + [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8], + [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4] + ] +}; + +var options = { + seriesBarDistance: 10 +}; + +var responsiveOptions = [ + ['screen and (max-width: 640px)', { + seriesBarDistance: 5, + axisX: { + labelInterpolationFnc: function (value) { + return value[0]; + } + } + }] +]; + +new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/pie-with-custom-labels.js b/site/templates/examples/pie-with-custom-labels.js new file mode 100644 index 00000000..3ddf2c51 --- /dev/null +++ b/site/templates/examples/pie-with-custom-labels.js @@ -0,0 +1,27 @@ +var data = { + labels: ['Bananas', 'Apples', 'Grapes'], + series: [20, 15, 40] +}; + +var options = { + labelInterpolationFnc: function(value) { + return value[0] + } +}; + +var responsiveOptions = [ + ['screen and (min-width: 640px)', { + chartPadding: 30, + labelOffset: 100, + labelDirection: 'explode', + labelInterpolationFnc: function(value) { + return value; + } + }], + ['screen and (min-width: 1024px)', { + labelOffset: 80, + chartPadding: 20 + }] +]; + +new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/simple-configuration-chart.js b/site/templates/examples/simple-configuration-chart.js new file mode 100644 index 00000000..7d3b8ced --- /dev/null +++ b/site/templates/examples/simple-configuration-chart.js @@ -0,0 +1,38 @@ +// Our labels and three data series +var data = { + labels: ['Week1', 'Week2', 'Week3', 'Week4', 'Week5', 'Week6'], + series: [ + [5, 4, 3, 7, 5, 10], + [3, 2, 9, 5, 4, 6], + [2, 1, -3, -4, -2, 0] + ] +}; + +// We are setting a few options for our chart and override the defaults +var options = { + // Don't draw the line chart points + showPoint: false, + // Disable line smoothing + lineSmooth: false, + // X-Axis specific configuration + axisX: { + // We can disable the grid for this axis + showGrid: false, + // and also don't show the label + showLabel: false + }, + // Y-Axis specific configuration + axisY: { + // Lets offset the chart a bit from the labels + offset: 40, + // The label interpolation function enables you to modify the values + // used for the labels on each axis. Here we are converting the + // values into million pound. + labelInterpolationFnc: function(value) { + return '$' + value + 'm'; + } + } +}; + +// All you need to do is pass your configuration as third parameter to the chart function +new Chartist.Line('.ct-chart', data, options); \ No newline at end of file diff --git a/site/templates/examples/simple-gauge-chart.js b/site/templates/examples/simple-gauge-chart.js new file mode 100644 index 00000000..c7ffec9c --- /dev/null +++ b/site/templates/examples/simple-gauge-chart.js @@ -0,0 +1,9 @@ +new Chartist.Pie('.ct-chart', { + series: [20, 10, 30, 40] +}, { + donut: true, + donutWidth: 60, + startAngle: 270, + total: 200, + showLabel: false +}); \ No newline at end of file diff --git a/site/templates/examples/simple-line-chart.js b/site/templates/examples/simple-line-chart.js new file mode 100644 index 00000000..bffe7c3a --- /dev/null +++ b/site/templates/examples/simple-line-chart.js @@ -0,0 +1,8 @@ +new Chartist.Line('.ct-chart', { + labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + series: [ + [12, 9, 7, 8, 5], + [2, 1, 3.5, 7, 3], + [1, 3, 4, 5, 6] + ] +}); \ No newline at end of file diff --git a/site/templates/examples/simple-pie-chart.js b/site/templates/examples/simple-pie-chart.js new file mode 100644 index 00000000..3417aa1b --- /dev/null +++ b/site/templates/examples/simple-pie-chart.js @@ -0,0 +1,11 @@ +var data = { + series: [5, 3, 4] +}; + +var sum = function(a, b) { return a + b }; + +new Chartist.Pie('.ct-chart', data, { + labelInterpolationFnc: function(value) { + return Math.round(value / data.series.reduce(sum) * 100) + '%'; + } +}); \ No newline at end of file diff --git a/source/site/getting-started.hbs b/site/templates/getting-started.hbs similarity index 100% rename from source/site/getting-started.hbs rename to site/templates/getting-started.hbs diff --git a/source/site/helpers/chartist-helpers.js b/site/templates/helpers/chartist-helpers.js similarity index 75% rename from source/site/helpers/chartist-helpers.js rename to site/templates/helpers/chartist-helpers.js index 465f9d56..88be2250 100644 --- a/source/site/helpers/chartist-helpers.js +++ b/site/templates/helpers/chartist-helpers.js @@ -8,11 +8,11 @@ module.exports.register = function (Handlebars, opt, params) { var helpers = { snippetPath: function (snippetId, snippetLang) { - return 'source/site/code-snippets/' + snippetId + '.' + snippetLang || 'js'; + return 'site/code-snippets/' + snippetId + '.' + snippetLang || 'js'; }, exampleCode: function(exampleId) { - return new Buffer(fs.readFileSync('source/site/examples/' + exampleId + '.js', { + return new Buffer(fs.readFileSync('site/examples/' + exampleId + '.js', { encoding: 'utf8' }), 'utf8').toString('base64'); } diff --git a/source/site/helpers/common-helpers.js b/site/templates/helpers/common-helpers.js similarity index 100% rename from source/site/helpers/common-helpers.js rename to site/templates/helpers/common-helpers.js diff --git a/source/site/helpers/dox-helpers.js b/site/templates/helpers/dox-helpers.js similarity index 100% rename from source/site/helpers/dox-helpers.js rename to site/templates/helpers/dox-helpers.js diff --git a/source/site/helpers/lorem-helper.js b/site/templates/helpers/lorem-helper.js similarity index 100% rename from source/site/helpers/lorem-helper.js rename to site/templates/helpers/lorem-helper.js diff --git a/source/site/index.hbs b/site/templates/index.hbs similarity index 100% rename from source/site/index.hbs rename to site/templates/index.hbs diff --git a/source/site/layouts/content.hbs b/site/templates/layouts/content.hbs similarity index 100% rename from source/site/layouts/content.hbs rename to site/templates/layouts/content.hbs diff --git a/source/site/layouts/default.hbs b/site/templates/layouts/default.hbs similarity index 79% rename from source/site/layouts/default.hbs rename to site/templates/layouts/default.hbs index afd2207a..a89eaa3b 100644 --- a/source/site/layouts/default.hbs +++ b/site/templates/layouts/default.hbs @@ -13,12 +13,12 @@ {{ title }} - + - - + + @@ -36,8 +36,8 @@ ga('send', 'pageview'); - - + + @@ -51,18 +51,18 @@ - - - - - - - - + + + + + + + + - - + + diff --git a/source/site/layouts/landing.hbs b/site/templates/layouts/landing.hbs similarity index 88% rename from source/site/layouts/landing.hbs rename to site/templates/layouts/landing.hbs index f1e29a36..b54704a8 100644 --- a/source/site/layouts/landing.hbs +++ b/site/templates/layouts/landing.hbs @@ -12,7 +12,7 @@ layout: default
    @@ -27,4 +27,4 @@ layout: default {{> body }} - \ No newline at end of file + diff --git a/source/site/partials/api-side-navigation.hbs b/site/templates/partials/api-side-navigation.hbs similarity index 100% rename from source/site/partials/api-side-navigation.hbs rename to site/templates/partials/api-side-navigation.hbs diff --git a/source/site/partials/browser-support-table.hbs b/site/templates/partials/browser-support-table.hbs similarity index 100% rename from source/site/partials/browser-support-table.hbs rename to site/templates/partials/browser-support-table.hbs diff --git a/source/site/partials/code-snippet.hbs b/site/templates/partials/code-snippet.hbs similarity index 100% rename from source/site/partials/code-snippet.hbs rename to site/templates/partials/code-snippet.hbs diff --git a/source/site/partials/code.hbs b/site/templates/partials/code.hbs similarity index 100% rename from source/site/partials/code.hbs rename to site/templates/partials/code.hbs diff --git a/source/site/partials/dox/dox-member.hbs b/site/templates/partials/dox/dox-member.hbs similarity index 100% rename from source/site/partials/dox/dox-member.hbs rename to site/templates/partials/dox/dox-member.hbs diff --git a/source/site/partials/dox/dox-module.hbs b/site/templates/partials/dox/dox-module.hbs similarity index 100% rename from source/site/partials/dox/dox-module.hbs rename to site/templates/partials/dox/dox-module.hbs diff --git a/source/site/partials/dox/dox-section.hbs b/site/templates/partials/dox/dox-section.hbs similarity index 100% rename from source/site/partials/dox/dox-section.hbs rename to site/templates/partials/dox/dox-section.hbs diff --git a/source/site/partials/example-chart.hbs b/site/templates/partials/example-chart.hbs similarity index 100% rename from source/site/partials/example-chart.hbs rename to site/templates/partials/example-chart.hbs diff --git a/source/site/partials/heading.hbs b/site/templates/partials/heading.hbs similarity index 100% rename from source/site/partials/heading.hbs rename to site/templates/partials/heading.hbs diff --git a/source/site/partials/hint.hbs b/site/templates/partials/hint.hbs similarity index 100% rename from source/site/partials/hint.hbs rename to site/templates/partials/hint.hbs diff --git a/source/site/partials/live-example.hbs b/site/templates/partials/live-example.hbs similarity index 100% rename from source/site/partials/live-example.hbs rename to site/templates/partials/live-example.hbs diff --git a/source/site/partials/navigation.hbs b/site/templates/partials/navigation.hbs similarity index 93% rename from source/site/partials/navigation.hbs rename to site/templates/partials/navigation.hbs index 7a15d6cf..f6ccea95 100644 --- a/source/site/partials/navigation.hbs +++ b/site/templates/partials/navigation.hbs @@ -9,7 +9,7 @@
      @@ -20,4 +20,4 @@
    - \ No newline at end of file + diff --git a/source/site/partials/section.hbs b/site/templates/partials/section.hbs similarity index 100% rename from source/site/partials/section.hbs rename to site/templates/partials/section.hbs diff --git a/source/site/partials/side-navigation.hbs b/site/templates/partials/side-navigation.hbs similarity index 100% rename from source/site/partials/side-navigation.hbs rename to site/templates/partials/side-navigation.hbs diff --git a/source/site/partials/sub-section.hbs b/site/templates/partials/sub-section.hbs similarity index 100% rename from source/site/partials/sub-section.hbs rename to site/templates/partials/sub-section.hbs diff --git a/source/site/partials/table.hbs b/site/templates/partials/table.hbs similarity index 100% rename from source/site/partials/table.hbs rename to site/templates/partials/table.hbs diff --git a/source/site/partials/text.hbs b/site/templates/partials/text.hbs similarity index 100% rename from source/site/partials/text.hbs rename to site/templates/partials/text.hbs diff --git a/source/scripts/chartist.bar.js b/source/scripts/chartist.bar.js deleted file mode 100644 index 04525a06..00000000 --- a/source/scripts/chartist.bar.js +++ /dev/null @@ -1,248 +0,0 @@ -/** - * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. - * - * @module Chartist.Bar - */ -/* global Chartist */ -(function(window, document, Chartist){ - 'use strict'; - - var defaultOptions = { - axisX: { - offset: 30, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 40, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 20 - }, - width: undefined, - height: undefined, - high: undefined, - low: undefined, - chartPadding: 5, - seriesBarDistance: 15, - classNames: { - chart: 'ct-chart-bar', - label: 'ct-label', - labelGroup: 'ct-labels', - series: 'ct-series', - bar: 'ct-bar', - grid: 'ct-grid', - gridGroup: 'ct-grids', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }; - - function createChart(options) { - var seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); - - // Create new svg element - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - - // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); - - var chartRect = Chartist.createChartRect(this.svg, options); - // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup), - // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - - // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = i - (this.data.series.length - 1) / 2, - // Half of the period with between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; - - seriesGroups[i] = this.svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), - bar; - - // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors - p.x += periodHalfWidth + (biPol * options.seriesBarDistance); - - bar = seriesGroups[i].elem('line', { - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }, options.classNames.bar).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'bar', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: bar, - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }); - } - } - - this.eventEmitter.emit('created', { - bounds: bounds, - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new bar chart and returns API object that you can use for later changes. - * - * @memberof Chartist.Bar - * @param {String|Node} query A selector query string or directly a DOM element - * @param {Object} data The data object that needs to consist of a labels and a series array - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object which exposes the API for the created chart - * - * @example - * // These are the default options of the bar chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the chart drawing area to the border of the container - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the chart drawing area to the border of the container - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Specify the distance in pixel of bars in a group - * seriesBarDistance: 15, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-bar', - * label: 'ct-label', - * labelGroup: 'ct-labels', - * series: 'ct-series', - * bar: 'ct-bar', - * grid: 'ct-grid', - * gridGroup: 'ct-grids', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example - * // Create a simple bar chart - * var data = { - * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // 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. - * new Chartist.Bar('.ct-chart', data); - * - * @example - * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 - * new Chartist.Bar('.ct-chart', { - * labels: [1, 2, 3, 4, 5, 6, 7], - * series: [ - * [1, 3, 2, -5, -3, 1, -6], - * [-5, -2, -4, -1, 2, -3, 1] - * ] - * }, { - * seriesBarDistance: 12, - * low: -10, - * high: 10 - * }); - * - */ - function Bar(query, data, options, responsiveOptions) { - Chartist.Bar.super.constructor.call(this, - query, - data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), - responsiveOptions); - } - - // Creating bar chart type in Chartist namespace - Chartist.Bar = Chartist.Base.extend({ - constructor: Bar, - createChart: createChart - }); - -}(window, document, Chartist)); diff --git a/source/scripts/chartist.base.js b/source/scripts/chartist.base.js deleted file mode 100644 index 89a6856f..00000000 --- a/source/scripts/chartist.base.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. - * - * @module Chartist.Base - */ -/* global Chartist */ -(function(window, document, Chartist) { - 'use strict'; - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Base - */ - function update() { - this.createChart(this.optionsProvider.currentOptions); - return this; - } - - /** - * 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. - * - * @memberof Chartist.Base - */ - function detach() { - window.removeEventListener('resize', this.resizeListener); - this.optionsProvider.removeMediaQueryListeners(); - return this; - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Base - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - this.eventEmitter.addEventHandler(event, handler); - return this; - } - - /** - * 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. - * - * @memberof Chartist.Base - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - this.eventEmitter.removeEventHandler(event, handler); - return this; - } - - /** - * Constructor of chart base class. - * - * @param query - * @param data - * @param options - * @param responsiveOptions - * @constructor - */ - function Base(query, data, options, responsiveOptions) { - this.container = Chartist.querySelector(query); - this.data = data; - this.options = options; - this.responsiveOptions = responsiveOptions; - this.eventEmitter = Chartist.EventEmitter(); - this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); - this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); - this.resizeListener = function resizeListener(){ - this.update(); - }.bind(this); - - if(this.container) { - // If chartist was already initialized in this container we are detaching all event listeners first - if(this.container.__chartist__) { - this.container.__chartist__.detach(); - } - - this.container.__chartist__ = this; - } - - window.addEventListener('resize', this.resizeListener); - - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - // TODO: Remove default options parameter from optionsProvider - this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter); - this.createChart(this.optionsProvider.currentOptions); - }.bind(this), 0); - } - - // Creating the chart base class - Chartist.Base = Chartist.Class.extend({ - constructor: Base, - optionsProvider: undefined, - container: undefined, - svg: undefined, - eventEmitter: undefined, - createChart: function() { - throw new Error('Base chart type can\'t be instantiated!'); - }, - update: update, - detach: detach, - on: on, - off: off, - version: Chartist.version, - supportsForeignObject: false - }); - -}(window, document, Chartist)); diff --git a/source/scripts/chartist.class.js b/source/scripts/chartist.class.js deleted file mode 100644 index 10c0c603..00000000 --- a/source/scripts/chartist.class.js +++ /dev/null @@ -1,217 +0,0 @@ -/** - * This module provides some basic prototype inheritance utilities. - * - * @module Chartist.Class - */ -/* global Chartist */ -(function(window, document, Chartist) { - 'use strict'; - - function listToArray(list) { - var arr = []; - if (list.length) { - for (var i = 0; i < list.length; i++) { - arr.push(list[i]); - } - } - return arr; - } - - /** - * Method to extend from current prototype. - * - * @memberof Chartist.Class - * @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. - * @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. - * @returns {Function} Constructor function of the new class - * - * @example - * var Fruit = Class.extend({ - * color: undefined, - * sugar: undefined, - * - * constructor: function(color, sugar) { - * this.color = color; - * this.sugar = sugar; - * }, - * - * eat: function() { - * this.sugar = 0; - * return this; - * } - * }); - * - * var Banana = Fruit.extend({ - * length: undefined, - * - * constructor: function(length, sugar) { - * Banana.super.constructor.call(this, 'Yellow', sugar); - * this.length = length; - * } - * }); - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - */ - function extend(properties, superProtoOverride) { - var superProto = superProtoOverride || this.prototype || Chartist.Class; - var proto = Object.create(superProto); - - Chartist.Class.cloneDefinitions(proto, properties); - - var constr = function() { - var fn = proto.constructor || function () {}, - instance; - - // If this is linked to the Chartist namespace the constructor was not called with new - // To provide a fallback we will instantiate here and return the instance - instance = this === Chartist ? Object.create(proto) : this; - fn.apply(instance, Array.prototype.slice.call(arguments, 0)); - - // If this constructor was not called with new we need to return the instance - // This will not harm when the constructor has been called with new as the returned value is ignored - return instance; - }; - - constr.prototype = proto; - constr.super = superProto; - constr.extend = this.extend; - - return constr; - } - - /** - * Creates a mixin from multiple super prototypes. - * - * @memberof Chartist.Class - * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. - * @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. - * @returns {Function} Constructor function of the newly created mixin class - * - * @example - * var Fruit = Class.extend({ - * color: undefined, - * sugar: undefined, - * - * constructor: function(color, sugar) { - * this.color = color; - * this.sugar = sugar; - * }, - * - * eat: function() { - * this.sugar = 0; - * return this; - * } - * }); - * - * var Banana = Fruit.extend({ - * length: undefined, - * - * constructor: function(length, sugar) { - * Banana.super.constructor.call(this, 'Yellow', sugar); - * this.length = length; - * } - * }); - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * - * var KCal = Class.extend({ - * sugar: 0, - * - * constructor: function(sugar) { - * this.sugar = sugar; - * }, - * - * get kcal() { - * return [this.sugar * 4, 'kcal'].join(''); - * } - * }); - * - * var Nameable = Class.extend({ - * name: undefined, - * - * constructor: function(name) { - * this.name = name; - * } - * }); - * - * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { - * constructor: function(name, length, sugar) { - * Nameable.prototype.constructor.call(this, name); - * Banana.prototype.constructor.call(this, length, sugar); - * }, - * - * toString: function() { - * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); - * } - * }); - * - * - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); - * console.log(superBanana.toString()); - * - */ - function mix(mixProtoArr, properties) { - if(this !== Chartist.Class) { - throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); - } - - // Make sure our mixin prototypes are the class objects and not the constructors - var superPrototypes = [{}] - .concat(mixProtoArr) - .map(function (prototype) { - return prototype instanceof Function ? prototype.prototype : prototype; - }); - - var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); - // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype - delete mixedSuperProto.constructor; - return this.extend(properties, mixedSuperProto); - } - - // Variable argument list clones args > 0 into args[0] and retruns modified args[0] - function cloneDefinitions() { - var args = listToArray(arguments); - var target = args[0]; - - args.splice(1, args.length - 1).forEach(function (source) { - Object.getOwnPropertyNames(source).forEach(function (propName) { - // If this property already exist in target we delete it first - delete target[propName]; - // Define the property with the descriptor from source - Object.defineProperty(target, propName, - Object.getOwnPropertyDescriptor(source, propName)); - }); - }); - - return target; - } - - Chartist.Class = { - extend: extend, - mix: mix, - cloneDefinitions: cloneDefinitions - }; - -}(window, document, Chartist)); diff --git a/source/scripts/chartist.core.js b/source/scripts/chartist.core.js deleted file mode 100644 index 7d2032be..00000000 --- a/source/scripts/chartist.core.js +++ /dev/null @@ -1,765 +0,0 @@ -/** - * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. - * - * @module Chartist.Core - */ -var Chartist = {}; -Chartist.version = '0.3.1'; - -(function (window, document, Chartist) { - 'use strict'; - - /** - * Helps to simplify functional style code - * - * @memberof Chartist.Core - * @param {*} n This exact value will be returned by the noop function - * @return {*} The same value that was provided to the n parameter - */ - Chartist.noop = function (n) { - return n; - }; - - /** - * Generates a-z from a number 0 to 26 - * - * @memberof Chartist.Core - * @param {Number} n A number from 0 to 26 that will result in a letter a-z - * @return {String} A character from a-z based on the input number n - */ - Chartist.alphaNumerate = function (n) { - // Limit to a-z - return String.fromCharCode(97 + n % 26); - }; - - // TODO: Make it possible to call extend with var args - /** - * Simple recursive object extend - * - * @memberof Chartist.Core - * @param {Object} target Target object where the source will be merged into - * @param {Object} source This object will be merged into target and then target is returned - * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source - */ - Chartist.extend = function (target, source) { - target = target || {}; - for (var prop in source) { - if (typeof source[prop] === 'object') { - target[prop] = Chartist.extend(target[prop], source[prop]); - } else { - target[prop] = source[prop]; - } - } - return target; - }; - - /** - * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {String|Number} value - * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel - */ - Chartist.stripUnit = function(value) { - if(typeof value === 'string') { - value = value.replace(/[^0-9\+-\.]/g, ''); - } - - return +value; - }; - - /** - * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {Number} value - * @param {String} unit - * @returns {String} Returns the passed number value with unit. - */ - Chartist.ensureUnit = function(value, unit) { - if(typeof value === 'number') { - value = value + unit; - } - - return value; - }; - - /** - * This is a wrapper around document.querySelector that will return the query if it's already of type Node - * - * @memberof Chartist.Core - * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly - * @return {Node} - */ - Chartist.querySelector = function(query) { - return query instanceof Node ? query : document.querySelector(query); - }; - - /** - * Create or reinitialize the SVG element for the chart - * - * @memberof Chartist.Core - * @param {Node} container The containing DOM Node object that will be used to plant the SVG element - * @param {String} width Set the width of the SVG element. Default is 100% - * @param {String} height Set the height of the SVG element. Default is 100% - * @param {String} className Specify a class to be added to the SVG element - * @return {Object} The created/reinitialized SVG element - */ - Chartist.createSvg = function (container, width, height, className) { - var svg; - - width = width || '100%'; - height = height || '100%'; - - svg = container.querySelector('svg'); - if(svg) { - container.removeChild(svg); - } - - // Create svg object with width and height or use 100% as default - svg = new Chartist.Svg('svg').attr({ - width: width, - height: height - }).addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' - }); - - // Add the DOM node to our container - container.appendChild(svg._node); - - return svg; - }; - - /** - * Convert data series into plain array - * - * @memberof Chartist.Core - * @param {Object} data The series object that contains the data to be visualized in the chart - * @return {Array} A plain array that contains the data to be visualized in the chart - */ - Chartist.getDataArray = function (data) { - var array = []; - - for (var i = 0; i < data.series.length; i++) { - // If the series array contains an object with a data property we will use the property - // otherwise the value directly (array or number) - array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? - data.series[i].data : data.series[i]; - - // Convert values to number - for (var j = 0; j < array[i].length; j++) { - array[i][j] = +array[i][j]; - } - } - - return array; - }; - - /** - * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. - * @param {Number} length The length of the x-axis data array. - * @return {Array} The array that got updated with missing values. - */ - Chartist.normalizeDataArray = function (dataArray, length) { - for (var i = 0; i < dataArray.length; i++) { - if (dataArray[i].length === length) { - continue; - } - - for (var j = dataArray[i].length; j < length; j++) { - dataArray[i][j] = 0; - } - } - - return dataArray; - }; - - /** - * Calculate the order of magnitude for the chart scale - * - * @memberof Chartist.Core - * @param {Number} value The value Range of the chart - * @return {Number} The order of magnitude - */ - Chartist.orderOfMagnitude = function (value) { - return Math.floor(Math.log(Math.abs(value)) / Math.LN10); - }; - - /** - * Project a data length into screen coordinates (pixels) - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Number} length Single data value from a series array - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Number} The projected data length in pixels - */ - Chartist.projectLength = function (svg, length, bounds, options) { - var availableHeight = Chartist.getAvailableHeight(svg, options); - return (length / bounds.range * availableHeight); - }; - - /** - * Get the height of the area in the chart for the data series - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Number} The height of the area in the chart for the data series - */ - Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); - }; - - /** - * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart - * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart. - */ - Chartist.getHighLow = function (dataArray) { - var i, - j, - highLow = { - high: -Number.MAX_VALUE, - low: Number.MAX_VALUE - }; - - for (i = 0; i < dataArray.length; i++) { - for (j = 0; j < dataArray[i].length; j++) { - if (dataArray[i][j] > highLow.high) { - highLow.high = dataArray[i][j]; - } - - if (dataArray[i][j] < highLow.low) { - highLow.low = dataArray[i][j]; - } - } - } - - return highLow; - }; - - // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude - /** - * Calculate and retrieve all the bounds for the chart and return them in one array - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Array} normalizedData The array that got updated with missing values. - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Number} referenceValue The reference value for the chart. - * @return {Object} All the values to set the bounds of the chart - */ - Chartist.getBounds = function (svg, normalizedData, options, referenceValue) { - var i, - newMin, - newMax, - bounds = Chartist.getHighLow(normalizedData); - - // Overrides of high / low from settings - bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); - bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); - - // If high and low are the same because of misconfiguration or flat data (only the same value) we need - // to set the high or low to 0 depending on the polarity - if(bounds.high === bounds.low) { - // If both values are 0 we set high to 1 - if(bounds.low === 0) { - bounds.high = 1; - } else if(bounds.low < 0) { - // If we have the same negative value for the bounds we set bounds.high to 0 - bounds.high = 0; - } else { - // If we have the same positive value for the bounds we set bounds.low to 0 - bounds.low = 0; - } - } - - // Overrides of high / low based on reference value, it will make sure that the invisible reference value is - // used to generate the chart. This is useful when the chart always needs to contain the position of the - // invisible reference value in the view i.e. for bipolar scales. - if (referenceValue || referenceValue === 0) { - bounds.high = Math.max(referenceValue, bounds.high); - bounds.low = Math.min(referenceValue, bounds.low); - } - - bounds.valueRange = bounds.high - bounds.low; - bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); - bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.range = bounds.max - bounds.min; - bounds.step = Math.pow(10, bounds.oom); - bounds.numberOfSteps = Math.round(bounds.range / bounds.step); - - // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace - // If we are already below the scaleMinSpace value we will scale up - var length = Chartist.projectLength(svg, bounds.step, bounds, options), - scaleUp = length < options.axisY.scaleMinSpace; - - while (true) { - if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { - bounds.step *= 2; - } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { - bounds.step /= 2; - } else { - break; - } - } - - // Narrow min and max based on new step - newMin = bounds.min; - newMax = bounds.max; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - if (i + bounds.step < bounds.low) { - newMin += bounds.step; - } - - if (i - bounds.step >= bounds.high) { - newMax -= bounds.step; - } - } - bounds.min = newMin; - bounds.max = newMax; - bounds.range = bounds.max - bounds.min; - - bounds.values = []; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - bounds.values.push(i); - } - - return bounds; - }; - - /** - * Calculate cartesian coordinates of polar coordinates - * - * @memberof Chartist.Core - * @param {Number} centerX X-axis coordinates of center point of circle segment - * @param {Number} centerY X-axis coordinates of center point of circle segment - * @param {Number} radius Radius of circle segment - * @param {Number} angleInDegrees Angle of circle segment in degrees - * @return {Number} Coordinates of point on circumference - */ - Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { - var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; - - return { - x: centerX + (radius * Math.cos(angleInRadians)), - y: centerY + (radius * Math.sin(angleInRadians)) - }; - }; - - /** - * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements - */ - Chartist.createChartRect = function (svg, options) { - var yOffset = options.axisY ? options.axisY.offset : 0, - xOffset = options.axisX ? options.axisX.offset : 0; - - return { - x1: options.chartPadding + yOffset, - y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), - y2: options.chartPadding, - width: function () { - return this.x2 - this.x1; - }, - height: function () { - return this.y1 - this.y2; - } - }; - }; - - /** - * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. - * - * @param {Object} parent The SVG element where the label should be created as a child - * @param {String} text The label text - * @param {Object} attributes An object with all attributes that should be set on the label element - * @param {String} className The class names that should be set for this element - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - * @returns {Object} The newly created SVG element - */ - Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { - if(supportsForeignObject) { - var content = '' + text + ''; - return parent.foreignObject(content, attributes); - } else { - return parent.elem('text', attributes, className).text(text); - } - }; - - /** - * Generate grid lines and labels for the x-axis into grid and labels group SVG elements - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} data The Object that contains the data to be visualized in the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create X-Axis - data.labels.forEach(function (value, index) { - var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - width = chartRect.width() / data.labels.length, - height = options.axisX.offset, - pos = chartRect.x1 + width * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { - return; - } - - if (options.axisX.showGrid) { - var gridElement = grid.elem('line', { - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }, [options.classNames.grid, options.classNames.horizontal].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'x', - index: index, - group: grid, - element: gridElement, - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }); - } - - if (options.axisX.showLabel) { - var labelPosition = { - x: pos + options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); - - eventEmitter.emit('draw', { - type: 'label', - axis: 'x', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.width; - } - }); - } - }); - }; - - /** - * Generate grid lines and labels for the y-axis into grid and labels group SVG elements - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create Y-Axis - bounds.values.forEach(function (value, index) { - var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - width = options.axisY.offset, - height = chartRect.height() / bounds.values.length, - pos = chartRect.y1 - height * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { - return; - } - - if (options.axisY.showGrid) { - var gridElement = grid.elem('line', { - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }, [options.classNames.grid, options.classNames.vertical].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'y', - index: index, - group: grid, - element: gridElement, - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }); - } - - if (options.axisY.showLabel) { - var labelPosition = { - x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), - y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); - - eventEmitter.emit('draw', { - type: 'label', - axis: 'y', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.height; - } - }); - } - }); - }; - - /** - * Determine the current point on the svg element to draw the data series - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Number} index The index of the current project point - * @return {Object} The coordinates object of the current project point containing an x and y number property - */ - Chartist.projectPoint = function (chartRect, bounds, data, index) { - return { - x: chartRect.x1 + chartRect.width() / data.length * index, - y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) - }; - }; - - // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one - /** - * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches - * - * @memberof Chartist.Core - * @param {Object} defaultOptions Default options from Chartist - * @param {Object} options Options set by user - * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart - * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events - * @return {Object} The consolidated options object from the defaults, base and matching responsive options - */ - Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions, eventEmitter) { - var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options), - currentOptions, - mediaQueryListeners = [], - i; - - function updateCurrentOptions() { - var previousOptions = currentOptions; - currentOptions = Chartist.extend({}, baseOptions); - - if (responsiveOptions) { - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); - if (mql.matches) { - currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]); - } - } - } - - if(eventEmitter) { - eventEmitter.emit('optionsChanged', { - previousOptions: previousOptions, - currentOptions: currentOptions - }); - } - } - - function removeMediaQueryListeners() { - mediaQueryListeners.forEach(function(mql) { - mql.removeListener(updateCurrentOptions); - }); - } - - if (!window.matchMedia) { - throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; - } else if (responsiveOptions) { - - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); - mql.addListener(updateCurrentOptions); - mediaQueryListeners.push(mql); - } - } - // Execute initially so we get the correct options - updateCurrentOptions(); - - return { - get currentOptions() { - return Chartist.extend({}, currentOptions); - }, - removeMediaQueryListeners: removeMediaQueryListeners - }; - }; - - //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas - /** - * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property - * where deltas for specific object properties can be found for the given object nesting level. For nested objects the - * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also - * contain a __delta__ property with the deltas of their level. - * - * @param {Object|Array} a Object that should be used to analyzed delta to object b - * @param {Object|Array} b The second object where the deltas from a should be analyzed - * @returns {Object} Delta descriptor object or null - */ - Chartist.deltaDescriptor = function(a, b) { - var summary = { - added: 0, - removed: 0, - modified: 0 - }; - - function findDeltasRecursively(a, b) { - var descriptor = { - __delta__: {} - }; - - // First check for removed and modified properties - Object.keys(a).forEach(function(property) { - if(!b.hasOwnProperty(property)) { - descriptor.__delta__[property] = { - type: 'remove', - property: property, - ours: a[property] - }; - summary.removed++; - } else { - if(typeof a[property] === 'object') { - var subDescriptor = findDeltasRecursively(a[property], b[property]); - if(subDescriptor) { - descriptor[property] = subDescriptor; - } - } else { - if(a[property] !== b[property]) { - descriptor.__delta__[property] = { - type: 'modify', - property: property, - ours: a[property], - theirs: b[property] - }; - summary.modified++; - } - } - } - }); - - // Check for added properties - Object.keys(b).forEach(function(property) { - if(!a.hasOwnProperty(property)) { - descriptor.__delta__[property] = { - type: 'added', - property: property, - theirs: b[property] - }; - summary.added++; - } - }); - - return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null; - } - - var delta = findDeltasRecursively(a, b); - if(delta) { - delta.__delta__.summary = summary; - } - - return delta; - }; - - //http://schepers.cc/getting-to-the-point - Chartist.catmullRom2bezier = function (crp, z) { - var d = []; - for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { - var p = [ - {x: +crp[i - 2], y: +crp[i - 1]}, - {x: +crp[i], y: +crp[i + 1]}, - {x: +crp[i + 2], y: +crp[i + 3]}, - {x: +crp[i + 4], y: +crp[i + 5]} - ]; - if (z) { - if (!i) { - p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; - } else if (iLen - 4 === i) { - p[3] = {x: +crp[0], y: +crp[1]}; - } else if (iLen - 2 === i) { - p[2] = {x: +crp[0], y: +crp[1]}; - p[3] = {x: +crp[2], y: +crp[3]}; - } - } else { - if (iLen - 4 === i) { - p[3] = p[2]; - } else if (!i) { - p[0] = {x: +crp[i], y: +crp[i + 1]}; - } - } - d.push( - [ - (-p[0].x + 6 * p[1].x + p[2].x) / 6, - (-p[0].y + 6 * p[1].y + p[2].y) / 6, - (p[1].x + 6 * p[2].x - p[3].x) / 6, - (p[1].y + 6 * p[2].y - p[3].y) / 6, - p[2].x, - p[2].y - ] - ); - } - - return d; - }; - -}(window, document, Chartist)); diff --git a/source/scripts/chartist.event.js b/source/scripts/chartist.event.js deleted file mode 100644 index 2b495f7b..00000000 --- a/source/scripts/chartist.event.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * A very basic event module that helps to generate and catch events. - * - * @module Chartist.Event - */ -/* global Chartist */ -(function (window, document, Chartist) { - 'use strict'; - - Chartist.EventEmitter = function () { - var handlers = []; - - /** - * Add an event handler for a specific event - * - * @memberof Chartist.Event - * @param {String} event The event name - * @param {Function} handler A event handler function - */ - function addEventHandler(event, handler) { - handlers[event] = handlers[event] || []; - handlers[event].push(handler); - } - - /** - * Remove an event handler of a specific event name or remove all event handlers for a specific event. - * - * @memberof Chartist.Event - * @param {String} event The event name where a specific or all handlers should be removed - * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. - */ - function removeEventHandler(event, handler) { - // Only do something if there are event handlers with this name existing - if(handlers[event]) { - // If handler is set we will look for a specific handler and only remove this - if(handler) { - handlers[event].splice(handlers[event].indexOf(handler), 1); - if(handlers[event].length === 0) { - delete handlers[event]; - } - } else { - // If no handler is specified we remove all handlers for this event - delete handlers[event]; - } - } - } - - /** - * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. - * - * @memberof Chartist.Event - * @param {String} event The event name that should be triggered - * @param {*} data Arbitrary data that will be passed to the event handler callback functions - */ - function emit(event, data) { - // Only do something if there are event handlers with this name existing - if(handlers[event]) { - handlers[event].forEach(function(handler) { - handler(data); - }); - } - - // Emit event to star event handlers - if(handlers['*']) { - handlers['*'].forEach(function(starHandler) { - starHandler(event, data); - }); - } - } - - return { - addEventHandler: addEventHandler, - removeEventHandler: removeEventHandler, - emit: emit - }; - }; - -}(window, document, Chartist)); diff --git a/source/scripts/chartist.line.js b/source/scripts/chartist.line.js deleted file mode 100644 index aea42aa6..00000000 --- a/source/scripts/chartist.line.js +++ /dev/null @@ -1,357 +0,0 @@ -/** - * 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. - * - * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. - * - * @module Chartist.Line - */ -/* global Chartist */ -(function(window, document, Chartist){ - 'use strict'; - - var defaultOptions = { - axisX: { - offset: 30, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 40, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 20 - }, - width: undefined, - height: undefined, - showLine: true, - showPoint: true, - showArea: false, - areaBase: 0, - lineSmooth: true, - low: undefined, - high: undefined, - chartPadding: 5, - 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', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }; - - function createChart(options) { - var seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); - - // Create new svg object - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - - // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options); - - var chartRect = Chartist.createChartRect(this.svg, options); - // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup); - - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - - // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - seriesGroups[i] = this.svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var p, - pathCoordinates = [], - point; - - for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); - pathCoordinates.push(p.x, p.y); - - //If we should show points we need to create them now to avoid secondary loop - // Small offset for Firefox to render squares correctly - if (options.showPoint) { - point = seriesGroups[i].elem('line', { - x1: p.x, - y1: p.y, - x2: p.x + 0.01, - y2: p.y - }, options.classNames.point).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'point', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: point, - x: p.x, - y: p.y - }); - } - } - - // TODO: Nicer handling of conditions, maybe composition? - if (options.showLine || options.showArea) { - // TODO: We should add a path API in the SVG library for easier path creation - var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; - - // If smoothed path and path has more than two points then use catmull rom to bezier algorithm - if (options.lineSmooth && pathCoordinates.length > 4) { - - var cr = Chartist.catmullRom2bezier(pathCoordinates); - for(var k = 0; k < cr.length; k++) { - pathElements.push('C' + cr[k].join()); - } - } else { - for(var l = 3; l < pathCoordinates.length; l += 2) { - pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); - } - } - - if(options.showArea) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); - - // If we need to draw area shapes we just make a copy of our pathElements SVG path array - var areaPathElements = pathElements.slice(); - - // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); - // And splice our new area path array to add the missing path elements to close the area shape - areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); - areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; - areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); - - // Create the new path for the area shape with the area class from the options - var area = seriesGroups[i].elem('path', { - d: areaPathElements.join('') - }, options.classNames.area, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'area', - values: normalizedData[i], - index: i, - group: seriesGroups[i], - element: area - }); - } - - if(options.showLine) { - var line = seriesGroups[i].elem('path', { - d: pathElements.join('') - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[i], - index: i, - group: seriesGroups[i], - element: line - }); - } - } - } - - this.eventEmitter.emit('created', { - bounds: bounds, - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new line chart. - * - * @memberof Chartist.Line - * @param {String|Node} query A selector query string or directly a DOM element - * @param {Object} data The data object that needs to consist of a labels and a series array - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object which exposes the API for the created chart - * - * @example - * // These are the default options of the line chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the labels to the chart area - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the labels to the chart area - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // If the line should be drawn or not - * showLine: true, - * // If dots should be drawn or not - * showPoint: true, - * // If the line chart should draw an area - * showArea: false, - * // The base for the area chart that will be used to close the area shape (is normally 0) - * areaBase: 0, - * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) - * lineSmooth: true, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * 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', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example - * // Create a simple line chart - * var data = { - * // A labels array that can contain any sort of values - * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], - * // Our series array that contains series objects or in this case series data arrays - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // As options we currently only set a static size of 300x200 px - * var options = { - * width: '300px', - * height: '200px' - * }; - * - * // 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 - * new Chartist.Line('.ct-chart', data, options); - * - * @example - * // Create a line chart with responsive options - * - * var data = { - * // A labels array that can contain any sort of values - * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], - * // Our series array that contains series objects or in this case series data arrays - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. - * var responsiveOptions = [ - * ['screen and (min-width: 641px) and (max-width: 1024px)', { - * showPoint: false, - * axisX: { - * labelInterpolationFnc: function(value) { - * // Will return Mon, Tue, Wed etc. on medium screens - * return value.slice(0, 3); - * } - * } - * }], - * ['screen and (max-width: 640px)', { - * showLine: false, - * axisX: { - * labelInterpolationFnc: function(value) { - * // Will return M, T, W etc. on small screens - * return value[0]; - * } - * } - * }] - * ]; - * - * new Chartist.Line('.ct-chart', data, null, responsiveOptions); - * - */ - function Line(query, data, options, responsiveOptions) { - Chartist.Line.super.constructor.call(this, - query, - data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), - responsiveOptions); - } - - // Creating line chart type in Chartist namespace - Chartist.Line = Chartist.Base.extend({ - constructor: Line, - createChart: createChart - }); - -}(window, document, Chartist)); diff --git a/source/scripts/chartist.pie.js b/source/scripts/chartist.pie.js deleted file mode 100644 index 2edf763d..00000000 --- a/source/scripts/chartist.pie.js +++ /dev/null @@ -1,291 +0,0 @@ -/** - * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts - * - * @module Chartist.Pie - */ -/* global Chartist */ -(function(window, document, Chartist) { - 'use strict'; - - var defaultOptions = { - width: undefined, - height: undefined, - chartPadding: 5, - classNames: { - chart: 'ct-chart-pie', - series: 'ct-series', - slice: 'ct-slice', - donut: 'ct-donut', - label: 'ct-label' - }, - startAngle: 0, - total: undefined, - donut: false, - donutWidth: 60, - showLabel: true, - labelOffset: 0, - labelInterpolationFnc: Chartist.noop, - labelOverflow: false, - labelDirection: 'neutral' - }; - - function determineAnchorPosition(center, label, direction) { - var toTheRight = label.x > center.x; - - if(toTheRight && direction === 'explode' || - !toTheRight && direction === 'implode') { - return 'start'; - } else if(toTheRight && direction === 'implode' || - !toTheRight && direction === 'explode') { - return 'end'; - } else { - return 'middle'; - } - } - - function createChart(options) { - var seriesGroups = [], - chartRect, - radius, - labelRadius, - totalDataSum, - startAngle = options.startAngle, - dataArray = Chartist.getDataArray(this.data); - - // Create SVG.js draw - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - // Calculate charting rect - chartRect = Chartist.createChartRect(this.svg, options, 0, 0); - // Get biggest circle radius possible within chartRect - radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); - // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { - return previousValue + currentValue; - }, 0); - - // 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 ? options.donutWidth / 2 : 0; - - // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius - // see https://github.com/gionkunz/chartist-js/issues/21 - labelRadius = options.donut ? radius : radius / 2; - // Add the offset to the labelRadius where a negative offset means closed to the center of the chart - labelRadius += options.labelOffset; - - // Calculate end angle based on total sum and current data value and offset with padding - var center = { - x: chartRect.x1 + chartRect.width() / 2, - y: chartRect.y2 + chartRect.height() / 2 - }; - - // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = this.data.series.filter(function(val) { - return val !== 0; - }).length === 1; - - // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - seriesGroups[i] = this.svg.elem('g', null, null, true); - - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var endAngle = startAngle + dataArray[i] / totalDataSum * 360; - // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle - // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; - } - - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), - end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), - arcSweep = endAngle - startAngle <= 180 ? '0' : '1', - d = [ - // Start at the end point from the cartesian coordinates - 'M', end.x, end.y, - // Draw arc - 'A', radius, radius, 0, arcSweep, 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 === false) { - d.push('L', center.x, center.y); - } - - // Create the SVG path - // If this is a donut chart we add the donut class, otherwise just a regular slice - var path = seriesGroups[i].elem('path', { - d: d.join(' ') - }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); - - // Adding the pie series value to the path - path.attr({ - 'value': dataArray[i] - }, Chartist.xmlNs.uri); - - // If this is a donut, we add the stroke-width as style attribute - if(options.donut === true) { - path.attr({ - 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' - }); - } - - // Fire off draw event - this.eventEmitter.emit('draw', { - type: 'slice', - value: dataArray[i], - totalDataSum: totalDataSum, - index: i, - group: seriesGroups[i], - element: path, - center: center, - radius: radius, - startAngle: startAngle, - endAngle: endAngle - }); - - // If we need to show labels we need to add the label for this slice now - if(options.showLabel) { - // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); - - var labelElement = seriesGroups[i].elem('text', { - dx: labelPosition.x, - dy: labelPosition.y, - 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) - }, options.classNames.label).text('' + interpolatedValue); - - // Fire off draw event - this.eventEmitter.emit('draw', { - type: 'label', - index: i, - group: seriesGroups[i], - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y - }); - } - - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues - // (except for last slice) - startAngle = endAngle; - } - - this.eventEmitter.emit('created', { - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new pie chart and returns an object that can be used to redraw the chart. - * - * @memberof Chartist.Pie - * @param {String|Node} query A selector query string or directly a DOM element - * @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. - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object with a version and an update method to manually redraw the chart - * - * @example - * // Default options of the pie chart - * var defaultOptions = { - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-pie', - * series: 'ct-series', - * slice: 'ct-slice', - * donut: 'ct-donut', - label: 'ct-label' - * }, - * // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. - * startAngle: 0, - * // 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. - * total: undefined, - * // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. - * donut: false, - * // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. - * donutWidth: 60, - * // If a label should be shown or not - * showLabel: true, - * // 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. - * labelOffset: 0, - * // An interpolation function for the label value - * labelInterpolationFnc: function(value, index) {return value;}, - * // 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. - * labelDirection: 'neutral' - * }; - * - * @example - * // Simple pie chart example with four series - * new Chartist.Pie('.ct-chart', { - * series: [10, 2, 4, 3] - * }); - * - * @example - * // Drawing a donut chart - * new Chartist.Pie('.ct-chart', { - * series: [10, 2, 4, 3] - * }, { - * donut: true - * }); - * - * @example - * // Using donut, startAngle and total to draw a gauge chart - * new Chartist.Pie('.ct-chart', { - * series: [20, 10, 30, 40] - * }, { - * donut: true, - * donutWidth: 20, - * startAngle: 270, - * total: 200 - * }); - * - * @example - * // Drawing a pie chart with padding and labels that are outside the pie - * new Chartist.Pie('.ct-chart', { - * series: [20, 10, 30, 40] - * }, { - * chartPadding: 30, - * labelOffset: 50, - * labelDirection: 'explode' - * }); - */ - function Pie(query, data, options, responsiveOptions) { - Chartist.Pie.super.constructor.call(this, - query, - data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), - responsiveOptions); - } - - // Creating pie chart type in Chartist namespace - Chartist.Pie = Chartist.Base.extend({ - constructor: Pie, - createChart: createChart, - determineAnchorPosition: determineAnchorPosition - }); - -}(window, document, Chartist)); diff --git a/source/scripts/chartist.svg.js b/source/scripts/chartist.svg.js deleted file mode 100644 index 2e598af5..00000000 --- a/source/scripts/chartist.svg.js +++ /dev/null @@ -1,582 +0,0 @@ -/** - * Chartist SVG module for simple SVG DOM abstraction - * - * @module Chartist.Svg - */ -/* global Chartist */ -(function(window, document, Chartist) { - 'use strict'; - - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; - - Chartist.xmlNs = { - qualifiedName: 'xmlns:ct', - prefix: 'ct', - uri: 'http://gionkunz.github.com/chartist-js/ct' - }; - - /** - * 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. - * - * @memberof Chartist.Svg - * @constructor - * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg - * @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. - * @param {String} className This class or class list will be added to the SVG element - * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child - * @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 - */ - function Svg(name, attributes, className, parent, insertFirst) { - // If Svg is getting called with an SVG element we just return the wrapper - if(name instanceof SVGElement) { - this._node = name; - } else { - this._node = document.createElementNS(svgNs, name); - - // If this is an SVG element created then custom namespace - if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); - } - - if(attributes) { - this.attr(attributes); - } - - if(className) { - this.addClass(className); - } - - if(parent) { - if (insertFirst && parent._node.firstChild) { - parent._node.insertBefore(this._node, parent._node.firstChild); - } else { - parent._node.appendChild(this._node); - } - } - } - } - - /** - * Set attributes on the current SVG element of the wrapper you're currently working on. - * - * @memberof Chartist.Svg - * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {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. - */ - function attr(attributes, ns) { - if(typeof attributes === 'string') { - if(ns) { - return this._node.getAttributeNS(ns, attributes); - } else { - return this._node.getAttribute(attributes); - } - } - - Object.keys(attributes).forEach(function(key) { - // If the attribute value is undefined we can skip this one - if(attributes[key] === undefined) { - return; - } - - if(ns) { - this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); - } else { - this._node.setAttribute(key, attributes[key]); - } - }.bind(this)); - - return this; - } - - /** - * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. - * - * @memberof Chartist.Svg - * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @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 - * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data - */ - function elem(name, attributes, className, insertFirst) { - return new Chartist.Svg(name, attributes, className, this, insertFirst); - } - - /** - * Returns the parent Chartist.SVG wrapper object - * - * @returns {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. - */ - function parent() { - return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; - } - - /** - * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. - * - * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element - */ - function root() { - var node = this._node; - while(node.nodeName !== 'svg') { - node = node.parentNode; - } - return new Chartist.Svg(node); - } - - /** - * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. - * - * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found - */ - function querySelector(selector) { - var foundNode = this._node.querySelector(selector); - return foundNode ? new Chartist.Svg(foundNode) : null; - } - - /** - * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. - * - * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found - */ - function querySelectorAll(selector) { - var foundNodes = this._node.querySelectorAll(selector); - return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; - } - - /** - * 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. - * - * @memberof Chartist.Svg - * @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 - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element - */ - function foreignObject(content, attributes, className, insertFirst) { - // If content is string then we convert it to DOM - // TODO: Handle case where content is not a string nor a DOM Node - if(typeof content === 'string') { - var container = document.createElement('div'); - container.innerHTML = content; - content = container.firstChild; - } - - // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); - - // Creating the foreignObject without required extension attribute (as described here - // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = this.elem('foreignObject', attributes, className, insertFirst); - - // Add content to foreignObjectElement - fnObj._node.appendChild(content); - - return fnObj; - } - - /** - * This method adds a new text element to the current Chartist.Svg wrapper. - * - * @memberof Chartist.Svg - * @param {String} t The text that should be added to the text element that is created - * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element - */ - function text(t) { - this._node.appendChild(document.createTextNode(t)); - return this; - } - - /** - * This method will clear all child nodes of the current wrapper object. - * - * @memberof Chartist.Svg - * @returns {Chartist.Svg} The same wrapper object that got emptied - */ - function empty() { - while (this._node.firstChild) { - this._node.removeChild(this._node.firstChild); - } - - return this; - } - - /** - * 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. - * - * @memberof Chartist.Svg - * @returns {Chartist.Svg} The parent wrapper object of the element that got removed - */ - function remove() { - this._node.parentNode.removeChild(this._node); - return new Chartist.Svg(this._node.parentNode); - } - - /** - * This method will replace the element with a new element that can be created outside of the current DOM. - * - * @memberof Chartist.Svg - * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object - * @returns {Chartist.Svg} The wrapper of the new element - */ - function replace(newElement) { - this._node.parentNode.replaceChild(newElement._node, this._node); - return newElement; - } - - /** - * This method will append an element to the current element as a child. - * - * @memberof Chartist.Svg - * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child - * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Chartist.Svg} The wrapper of the appended object - */ - function append(element, insertFirst) { - if(insertFirst && this._node.firstChild) { - this._node.insertBefore(element._node, this._node.firstChild); - } else { - this._node.appendChild(element._node); - } - - return this; - } - - /** - * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. - * - * @memberof Chartist.Svg - * @returns {Array} A list of classes or an empty array if there are no classes on the current element - */ - function classes() { - return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; - } - - /** - * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element - */ - function addClass(names) { - this._node.setAttribute('class', - this.classes(this._node) - .concat(names.trim().split(/\s+/)) - .filter(function(elem, pos, self) { - return self.indexOf(elem) === pos; - }).join(' ') - ); - - return this; - } - - /** - * Removes one or a space separated list of classes from the current element. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element - */ - function removeClass(names) { - var removedClasses = names.trim().split(/\s+/); - - this._node.setAttribute('class', this.classes(this._node).filter(function(name) { - return removedClasses.indexOf(name) === -1; - }).join(' ')); - - return this; - } - - /** - * Removes all classes from the current element. - * - * @memberof Chartist.Svg - * @returns {Chartist.Svg} The wrapper of the current element - */ - function removeAllClasses() { - this._node.setAttribute('class', ''); - - return this; - } - - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Svg - * @return {Number} The elements height in pixels - */ - function height() { - return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; - } - - /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @return {Number} The elements width in pixels - */ - function width() { - return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; - } - - /** - * 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. - * **An animations object could look like this:** - * ```javascript - * element.animate({ - * opacity: { - * dur: 1000, - * from: 0, - * to: 1 - * }, - * x1: { - * dur: '1000ms', - * from: 100, - * to: 200, - * easing: 'easeOutQuart' - * }, - * y1: { - * dur: '2s', - * from: 0, - * to: 100 - * } - * }); - * ``` - * **Automatic unit conversion** - * 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. - * **Guided mode** - * 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. - * If guided mode is enabled the following behavior is added: - * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation - * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) - * - The animate element will be forced to use `fill="freeze"` - * - 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. - * - After the animation the element attribute value will be set to the `to` value of the animation - * - The animate element is deleted from the DOM - * - * @memberof Chartist.Svg - * @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. - * @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. - * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. - * @returns {Chartist.Svg} The current element where the animation was added - */ - function animate(animations, guided, eventEmitter) { - if(guided === undefined) { - guided = true; - } - - Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { - - function createAnimate(animationDefinition, guided) { - var attributeProperties = {}, - animate, - timeout, - easing; - - // Check if an easing is specified in the definition object and delete it from the object as it will not - // be part of the animate element attributes. - if(animationDefinition.easing) { - // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object - easing = animationDefinition.easing instanceof Array ? - animationDefinition.easing : - Chartist.Svg.Easing[animationDefinition.easing]; - delete animationDefinition.easing; - } - - // If numeric dur or begin was provided we assume milli seconds - animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); - animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); - - if(easing) { - animationDefinition.calcMode = 'spline'; - animationDefinition.keySplines = easing.join(' '); - animationDefinition.keyTimes = '0;1'; - } - - // Adding "fill: freeze" if we are in guided mode and set initial attribute values - if(guided) { - animationDefinition.fill = 'freeze'; - // Animated property on our element should already be set to the animation from value in guided mode - attributeProperties[attribute] = animationDefinition.from; - this.attr(attributeProperties); - - // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin - // which needs to be in ms aside - timeout = Chartist.stripUnit(animationDefinition.begin || 0); - animationDefinition.begin = 'indefinite'; - } - - animate = this.elem('animate', Chartist.extend({ - attributeName: attribute - }, animationDefinition)); - - if(guided) { - // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout - setTimeout(function() { - animate._node.beginElement(); - }, timeout); - } - - if(eventEmitter) { - animate._node.addEventListener('beginEvent', function handleBeginEvent() { - eventEmitter.emit('animationBegin', { - element: this, - animate: animate._node, - params: animationDefinition - }); - }.bind(this)); - } - - animate._node.addEventListener('endEvent', function handleEndEvent() { - if(eventEmitter) { - eventEmitter.emit('animationEnd', { - element: this, - animate: animate._node, - params: animationDefinition - }); - } - - if(guided) { - // Set animated attribute to current animated value - attributeProperties[attribute] = animationDefinition.to; - this.attr(attributeProperties); - // Remove the animate element as it's no longer required - animate.remove(); - } - }.bind(this)); - } - - // If current attribute is an array of definition objects we create an animate for each and disable guided mode - if(animations[attribute] instanceof Array) { - animations[attribute].forEach(function(animationDefinition) { - createAnimate.bind(this)(animationDefinition, false); - }.bind(this)); - } else { - createAnimate.bind(this)(animations[attribute], guided); - } - - }.bind(this)); - - return this; - } - - Chartist.Svg = Chartist.Class.extend({ - constructor: Svg, - attr: attr, - elem: elem, - parent: parent, - root: root, - querySelector: querySelector, - querySelectorAll: querySelectorAll, - foreignObject: foreignObject, - text: text, - empty: empty, - remove: remove, - replace: replace, - append: append, - classes: classes, - addClass: addClass, - removeClass: removeClass, - removeAllClasses: removeAllClasses, - height: height, - width: width, - animate: animate - }); - - /** - * 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. - * - * @memberof Chartist.Svg - * @param {String} feature The SVG 1.1 feature that should be checked for support. - * @returns {Boolean} True of false if the feature is supported or not - */ - Chartist.Svg.isSupported = function(feature) { - return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); - }; - - /** - * 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. - * - * @memberof Chartist.Svg - */ - var easingCubicBeziers = { - easeInSine: [0.47, 0, 0.745, 0.715], - easeOutSine: [0.39, 0.575, 0.565, 1], - easeInOutSine: [0.445, 0.05, 0.55, 0.95], - easeInQuad: [0.55, 0.085, 0.68, 0.53], - easeOutQuad: [0.25, 0.46, 0.45, 0.94], - easeInOutQuad: [0.455, 0.03, 0.515, 0.955], - easeInCubic: [0.55, 0.055, 0.675, 0.19], - easeOutCubic: [0.215, 0.61, 0.355, 1], - easeInOutCubic: [0.645, 0.045, 0.355, 1], - easeInQuart: [0.895, 0.03, 0.685, 0.22], - easeOutQuart: [0.165, 0.84, 0.44, 1], - easeInOutQuart: [0.77, 0, 0.175, 1], - easeInQuint: [0.755, 0.05, 0.855, 0.06], - easeOutQuint: [0.23, 1, 0.32, 1], - easeInOutQuint: [0.86, 0, 0.07, 1], - easeInExpo: [0.95, 0.05, 0.795, 0.035], - easeOutExpo: [0.19, 1, 0.22, 1], - easeInOutExpo: [1, 0, 0, 1], - easeInCirc: [0.6, 0.04, 0.98, 0.335], - easeOutCirc: [0.075, 0.82, 0.165, 1], - easeInOutCirc: [0.785, 0.135, 0.15, 0.86], - easeInBack: [0.6, -0.28, 0.735, 0.045], - easeOutBack: [0.175, 0.885, 0.32, 1.275], - easeInOutBack: [0.68, -0.55, 0.265, 1.55] - }; - - Chartist.Svg.Easing = easingCubicBeziers; - - /** - * 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. - * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. - * - * @memberof Chartist.Svg - * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) - * @constructor - */ - function SvgList(nodeList) { - var list = this; - - this.svgElements = []; - for(var i = 0; i < nodeList.length; i++) { - this.svgElements.push(new Chartist.Svg(nodeList[i])); - } - - // Add delegation methods for Chartist.Svg - Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { - return ['constructor', - 'parent', - 'querySelector', - 'querySelectorAll', - 'replace', - 'append', - 'classes', - 'height', - 'width'].indexOf(prototypeProperty) === -1; - }).forEach(function(prototypeProperty) { - list[prototypeProperty] = function() { - var args = Array.prototype.slice.call(arguments, 0); - list.svgElements.forEach(function(element) { - Chartist.Svg.prototype[prototypeProperty].apply(element, args); - }); - return list; - }; - }); - } - - Chartist.Svg.List = Chartist.Class.extend({ - constructor: SvgList - }); - -}(window, document, Chartist)); diff --git a/source/site/code-snippets/custom-include.scss b/source/site/code-snippets/custom-include.scss deleted file mode 100644 index a9bcf228..00000000 --- a/source/site/code-snippets/custom-include.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import "http://github.com/_my-chartist-settings.scss"; -@import "http://github.com/chartist/libdist/scss/chartist.scss"; \ No newline at end of file diff --git a/source/site/code-snippets/simple-start.html b/source/site/code-snippets/simple-start.html deleted file mode 100644 index 7f328094..00000000 --- a/source/site/code-snippets/simple-start.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/source/styles/_modules.scss b/source/styles/_modules.scss deleted file mode 100644 index 41ecb6ca..00000000 --- a/source/styles/_modules.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import "http://github.com/modules/common"; -@import "http://github.com/modules/scale"; -@import "http://github.com/modules/animation"; diff --git a/source/styles/chartist.scss b/source/styles/chartist.scss deleted file mode 100644 index a8cfc7c2..00000000 --- a/source/styles/chartist.scss +++ /dev/null @@ -1,152 +0,0 @@ -@import "http://github.com/modules"; -@import "http://github.com/settings/chartist-settings"; - -@mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) { - display: block; - position: relative; - width: $width; - - &:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: $ratio * 100%; - } - - &:after { - content: ""; - display: table; - clear: both; - } - - > svg { - display: block; - position: absolute; - top: 0; - left: 0; - } -} - -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align) { - display: block; - width: 100%; - height: 100%; - fill: $ct-text-color; - color: $ct-text-color; - font-size: $ct-text-size; - text-align: $ct-text-align; -} - -@mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { - stroke: $ct-grid-color; - stroke-width: $ct-grid-width; - - @if ($ct-grid-dasharray) { - stroke-dasharray: $ct-grid-dasharray; - } -} - -@mixin ct-chart-point($ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape) { - stroke-width: $ct-point-size; - stroke-linecap: $ct-point-shape; -} - -@mixin ct-chart-line($ct-line-width: $ct-line-width, $ct-line-dasharray: $ct-line-dasharray) { - fill: none; - stroke-width: $ct-line-width; - - @if ($ct-line-dasharray) { - stroke-dasharray: $ct-line-dasharray; - } -} - -@mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) { - stroke: none; - fill-opacity: $ct-area-opacity; -} - -@mixin ct-chart-bar($ct-bar-width: $ct-bar-width) { - fill: none; - stroke-width: $ct-bar-width; -} - -@mixin ct-chart-donut($ct-donut-width: $ct-donut-width) { - fill: none; - stroke-width: $ct-donut-width; -} - -@mixin ct-chart-series-color($color) { - .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice}.#{$ct-class-donut} { - stroke: $color; - } - - .#{$ct-class-slice}:not(.#{$ct-class-donut}), .#{$ct-class-area} { - fill: $color; - } -} - -@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { - .#{$ct-class-label} { - @include ct-chart-label($ct-text-color, $ct-text-size); - } - - .#{$ct-class-label}.#{$ct-class-horizontal} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align); - } - - .#{$ct-class-label}.#{$ct-class-vertical} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align); - } - - .#{$ct-class-grid} { - @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); - } - - .#{$ct-class-point} { - @include ct-chart-point($ct-point-size, $ct-point-shape); - } - - .#{$ct-class-line} { - @include ct-chart-line($ct-line-width); - } - - .#{$ct-class-area} { - @include ct-chart-area(); - } - - .#{$ct-class-bar} { - @include ct-chart-bar($ct-bar-width); - } - - .#{$ct-class-slice}.#{$ct-class-donut} { - @include ct-chart-donut($ct-donut-width); - } - - @if $ct-include-colored-series { - .#{$ct-class-series} { - @for $i from 0 to length($ct-series-names) { - &.#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { - $color: nth($ct-series-colors, $i + 1); - - @include ct-chart-series-color($color); - } - } - } - } -} - -@if $ct-include-classes { - .#{$ct-class-chart} { - @include ct-chart(); - - @if $ct-include-alternative-responsive-containers { - @for $i from 0 to length($ct-scales-names) { - &.#{nth($ct-scales-names, $i + 1)} { - @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); - } - } - } - } -} \ No newline at end of file diff --git a/source/styles/modules/_animation.scss b/source/styles/modules/_animation.scss deleted file mode 100644 index 1af626a1..00000000 --- a/source/styles/modules/_animation.scss +++ /dev/null @@ -1,21 +0,0 @@ -@mixin keyframes($name) { - @-webkit-keyframes #{$name} { - @content; - } - @-moz-keyframes #{$name} { - @content; - } - @-ms-keyframes #{$name} { - @content; - } - @keyframes #{$name} { - @content; - } -} - -@mixin animation($name, $params) { - -webkit-animation: #{$name} $params; /* Safari 4+ */ - -moz-animation: #{$name} $params; /* Fx 5+ */ - -o-animation: #{$name} $params; /* Opera 12+ */ - animation: #{$name} $params; /* IE 10+ */ -} \ No newline at end of file diff --git a/source/styles/modules/_common.scss b/source/styles/modules/_common.scss deleted file mode 100644 index e29cd020..00000000 --- a/source/styles/modules/_common.scss +++ /dev/null @@ -1,15 +0,0 @@ -@function reverse($list, $recursive: false) { - $result: (); - - @for $i from length($list)*-1 through -1 { - @if type-of(nth($list, abs($i))) == list and $recursive { - $result: append($result, reverse(nth($list, abs($i)), $recursive)); - } - - @else { - $result: append($result, nth($list, abs($i))); - } - } - - @return $result; -} \ No newline at end of file diff --git a/source/styles/modules/_scale.scss b/source/styles/modules/_scale.scss deleted file mode 100644 index 1a7a3b7d..00000000 --- a/source/styles/modules/_scale.scss +++ /dev/null @@ -1,41 +0,0 @@ -$scale-minor-second: 15/16; -$scale-major-second: 8/9; -$scale-minor-third: 5/6; -$scale-major-third: 4/5; -$scale-perfect-fourth: 3/4; -$scale-perfect-fifth: 2/3; -$scale-minor-sixth: 5/8; -$scale-golden-section: 1/1.618; -$scale-major-sixth: 3/5; -$scale-minor-seventh: 9/16; -$scale-major-seventh: 8/15; -$scale-octave: 1/2; -$scale-major-tenth: 2/5; -$scale-major-eleventh: 3/8; -$scale-major-twelfth: 1/3; -$scale-double-octave: 1/4; - -@function generateScale($base: 16, $scale-type: $scale-golden-section, $limit-lower: 6, $limit-upper: 100) { - $scale: (); - $value: $base; - - @while $value > $limit-lower { - $value: $value * $scale-type; - @if $value > $limit-lower { - $scale: append($scale, $value); - } - } - - $scale: reverse($scale); - $scale: append($scale, $base); - - $value: $base; - @while $value < $limit-upper { - $value: $value / $scale-type; - @if $value < $limit-upper { - $scale: append($scale, $value); - } - } - - @return $scale; -} \ No newline at end of file diff --git a/source/styles/settings/_chartist-settings.scss b/source/styles/settings/_chartist-settings.scss deleted file mode 100644 index 059e3d8a..00000000 --- a/source/styles/settings/_chartist-settings.scss +++ /dev/null @@ -1,65 +0,0 @@ -// Scales for responsive SVG containers -$ct-scales: ((1), (15/16), (8/9), (5/6), (4/5), (3/4), (2/3), (5/8), (1/1.618), (3/5), (9/16), (8/15), (1/2), (2/5), (3/8), (1/3), (1/4)) !default; -$ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, ct-major-third, ct-perfect-fourth, ct-perfect-fifth, ct-minor-sixth, ct-golden-section, ct-major-sixth, ct-minor-seventh, ct-major-seventh, ct-octave, ct-major-tenth, ct-major-eleventh, ct-major-twelfth, ct-double-octave) !default; - -// Class names to be used when generating CSS -$ct-class-chart: ct-chart !default; -$ct-class-chart-line: ct-chart-line !default; -$ct-class-chart-bar: ct-chart-bar !default; -$ct-class-chart-pie: ct-chart-pie !default; -$ct-class-label: ct-label !default; -$ct-class-series: ct-series !default; -$ct-class-line: ct-line !default; -$ct-class-point: ct-point !default; -$ct-class-area: ct-area !default; -$ct-class-bar: ct-bar !default; -$ct-class-slice: ct-slice !default; -$ct-class-donut: ct-donut !default; -$ct-class-grid: ct-grid !default; -$ct-class-vertical: ct-vertical !default; -$ct-class-horizontal: ct-horizontal !default; - -// Container ratio -$ct-container-ratio: (1/1.618) !default; - -// Text styles for labels -$ct-text-color: rgba(0, 0, 0, 0.4) !default; -$ct-text-size: 0.75rem !default; -$ct-text-align: left !default; -$ct-horizontal-text-align: left !default; -$ct-vertical-text-align: right !default; - -// Grid styles -$ct-grid-color: rgba(0, 0, 0, 0.2) !default; -$ct-grid-dasharray: 2px !default; -$ct-grid-width: 1px !default; - -// Line chart properties -$ct-line-width: 4px !default; -$ct-line-dasharray: false !default; -$ct-point-size: 10px !default; -// Line chart point, can be either round or square -$ct-point-shape: round !default; -// Area fill transparency between 0 and 1 -$ct-area-opacity: 0.1 !default; - -// Bar chart bar width -$ct-bar-width: 10px !default; - -// Donut width (If donut width is to big it can cause issues where the shape gets distorted) -$ct-donut-width: 60px !default; - -// If set to true it will include the default classes and generate CSS output. If you're planning to use the mixins you -// should set this property to false -$ct-include-classes: true !default; - -// If this is set to true the CSS will contain colored series. You can extend or change the color with the -// properties below -$ct-include-colored-series: $ct-include-classes !default; - -// If set to true this will include all responsive container variations using the scales defined at the top of the script -$ct-include-alternative-responsive-containers: $ct-include-classes !default; - -// Series names and colors. This can be extended or customized as desired. Just add more series and colors. -$ct-series-names: (a, b, c, d) !default; -$ct-series-colors: (#d70206, #F05B4F, #F4C63D, #453D3F) !default; From fe847c84193c3a48a063690148873fbcf11bdb8c Mon Sep 17 00:00:00 2001 From: Autarc Date: Tue, 25 Nov 2014 09:50:03 +0100 Subject: [PATCH 093/593] organize source files --- src/base.js | 122 ++++ src/class.js | 217 ++++++ src/core.js | 766 ++++++++++++++++++++ src/event.js | 78 ++ src/styles/_modules.scss | 5 + src/styles/chartist.scss | 152 ++++ src/styles/modules/_animation.scss | 21 + src/styles/modules/_common.scss | 15 + src/styles/modules/_scale.scss | 41 ++ src/styles/settings/_chartist-settings.scss | 65 ++ src/svg.js | 582 +++++++++++++++ src/types/bar.js | 248 +++++++ src/types/line.js | 357 +++++++++ src/types/pie.js | 291 ++++++++ 14 files changed, 2960 insertions(+) create mode 100644 src/base.js create mode 100644 src/class.js create mode 100644 src/core.js create mode 100644 src/event.js create mode 100644 src/styles/_modules.scss create mode 100644 src/styles/chartist.scss create mode 100644 src/styles/modules/_animation.scss create mode 100644 src/styles/modules/_common.scss create mode 100644 src/styles/modules/_scale.scss create mode 100644 src/styles/settings/_chartist-settings.scss create mode 100644 src/svg.js create mode 100644 src/types/bar.js create mode 100644 src/types/line.js create mode 100644 src/types/pie.js diff --git a/src/base.js b/src/base.js new file mode 100644 index 00000000..89a6856f --- /dev/null +++ b/src/base.js @@ -0,0 +1,122 @@ +/** + * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. + * + * @module Chartist.Base + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container + /** + * Updates the chart which currently does a full reconstruction of the SVG DOM + * + * @memberof Chartist.Base + */ + function update() { + this.createChart(this.optionsProvider.currentOptions); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + */ + function detach() { + window.removeEventListener('resize', this.resizeListener); + this.optionsProvider.removeMediaQueryListeners(); + return this; + } + + /** + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. + * + * @memberof Chartist.Base + * @param {String} event Name of the event. Check the examples for supported events. + * @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. + */ + function on(event, handler) { + this.eventEmitter.addEventHandler(event, handler); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + * @param {String} event Name of the event for which a handler should be removed + * @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. + */ + function off(event, handler) { + this.eventEmitter.removeEventHandler(event, handler); + return this; + } + + /** + * Constructor of chart base class. + * + * @param query + * @param data + * @param options + * @param responsiveOptions + * @constructor + */ + function Base(query, data, options, responsiveOptions) { + this.container = Chartist.querySelector(query); + this.data = data; + this.options = options; + this.responsiveOptions = responsiveOptions; + this.eventEmitter = Chartist.EventEmitter(); + this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); + this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); + this.resizeListener = function resizeListener(){ + this.update(); + }.bind(this); + + if(this.container) { + // If chartist was already initialized in this container we are detaching all event listeners first + if(this.container.__chartist__) { + this.container.__chartist__.detach(); + } + + this.container.__chartist__ = this; + } + + window.addEventListener('resize', this.resizeListener); + + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + // TODO: Remove default options parameter from optionsProvider + this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter); + this.createChart(this.optionsProvider.currentOptions); + }.bind(this), 0); + } + + // Creating the chart base class + Chartist.Base = Chartist.Class.extend({ + constructor: Base, + optionsProvider: undefined, + container: undefined, + svg: undefined, + eventEmitter: undefined, + createChart: function() { + throw new Error('Base chart type can\'t be instantiated!'); + }, + update: update, + detach: detach, + on: on, + off: off, + version: Chartist.version, + supportsForeignObject: false + }); + +}(window, document, Chartist)); diff --git a/src/class.js b/src/class.js new file mode 100644 index 00000000..10c0c603 --- /dev/null +++ b/src/class.js @@ -0,0 +1,217 @@ +/** + * This module provides some basic prototype inheritance utilities. + * + * @module Chartist.Class + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + function listToArray(list) { + var arr = []; + if (list.length) { + for (var i = 0; i < list.length; i++) { + arr.push(list[i]); + } + } + return arr; + } + + /** + * Method to extend from current prototype. + * + * @memberof Chartist.Class + * @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. + * @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. + * @returns {Function} Constructor function of the new class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + */ + function extend(properties, superProtoOverride) { + var superProto = superProtoOverride || this.prototype || Chartist.Class; + var proto = Object.create(superProto); + + Chartist.Class.cloneDefinitions(proto, properties); + + var constr = function() { + var fn = proto.constructor || function () {}, + instance; + + // If this is linked to the Chartist namespace the constructor was not called with new + // To provide a fallback we will instantiate here and return the instance + instance = this === Chartist ? Object.create(proto) : this; + fn.apply(instance, Array.prototype.slice.call(arguments, 0)); + + // If this constructor was not called with new we need to return the instance + // This will not harm when the constructor has been called with new as the returned value is ignored + return instance; + }; + + constr.prototype = proto; + constr.super = superProto; + constr.extend = this.extend; + + return constr; + } + + /** + * Creates a mixin from multiple super prototypes. + * + * @memberof Chartist.Class + * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. + * @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. + * @returns {Function} Constructor function of the newly created mixin class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * + * var KCal = Class.extend({ + * sugar: 0, + * + * constructor: function(sugar) { + * this.sugar = sugar; + * }, + * + * get kcal() { + * return [this.sugar * 4, 'kcal'].join(''); + * } + * }); + * + * var Nameable = Class.extend({ + * name: undefined, + * + * constructor: function(name) { + * this.name = name; + * } + * }); + * + * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { + * constructor: function(name, length, sugar) { + * Nameable.prototype.constructor.call(this, name); + * Banana.prototype.constructor.call(this, length, sugar); + * }, + * + * toString: function() { + * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); + * } + * }); + * + * + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); + * console.log(superBanana.toString()); + * + */ + function mix(mixProtoArr, properties) { + if(this !== Chartist.Class) { + throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); + } + + // Make sure our mixin prototypes are the class objects and not the constructors + var superPrototypes = [{}] + .concat(mixProtoArr) + .map(function (prototype) { + return prototype instanceof Function ? prototype.prototype : prototype; + }); + + var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); + // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype + delete mixedSuperProto.constructor; + return this.extend(properties, mixedSuperProto); + } + + // Variable argument list clones args > 0 into args[0] and retruns modified args[0] + function cloneDefinitions() { + var args = listToArray(arguments); + var target = args[0]; + + args.splice(1, args.length - 1).forEach(function (source) { + Object.getOwnPropertyNames(source).forEach(function (propName) { + // If this property already exist in target we delete it first + delete target[propName]; + // Define the property with the descriptor from source + Object.defineProperty(target, propName, + Object.getOwnPropertyDescriptor(source, propName)); + }); + }); + + return target; + } + + Chartist.Class = { + extend: extend, + mix: mix, + cloneDefinitions: cloneDefinitions + }; + +}(window, document, Chartist)); diff --git a/src/core.js b/src/core.js new file mode 100644 index 00000000..7b37c5a1 --- /dev/null +++ b/src/core.js @@ -0,0 +1,766 @@ +/** + * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. + * + * @module Chartist.Core + */ +var Chartist = { + version: '0.4.1' +}; + +(function (window, document, Chartist) { + 'use strict'; + + /** + * Helps to simplify functional style code + * + * @memberof Chartist.Core + * @param {*} n This exact value will be returned by the noop function + * @return {*} The same value that was provided to the n parameter + */ + Chartist.noop = function (n) { + return n; + }; + + /** + * Generates a-z from a number 0 to 26 + * + * @memberof Chartist.Core + * @param {Number} n A number from 0 to 26 that will result in a letter a-z + * @return {String} A character from a-z based on the input number n + */ + Chartist.alphaNumerate = function (n) { + // Limit to a-z + return String.fromCharCode(97 + n % 26); + }; + + // TODO: Make it possible to call extend with var args + /** + * Simple recursive object extend + * + * @memberof Chartist.Core + * @param {Object} target Target object where the source will be merged into + * @param {Object} source This object will be merged into target and then target is returned + * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source + */ + Chartist.extend = function (target, source) { + target = target || {}; + for (var prop in source) { + if (typeof source[prop] === 'object') { + target[prop] = Chartist.extend(target[prop], source[prop]); + } else { + target[prop] = source[prop]; + } + } + return target; + }; + + /** + * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {String|Number} value + * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel + */ + Chartist.stripUnit = function(value) { + if(typeof value === 'string') { + value = value.replace(/[^0-9\+-\.]/g, ''); + } + + return +value; + }; + + /** + * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {Number} value + * @param {String} unit + * @returns {String} Returns the passed number value with unit. + */ + Chartist.ensureUnit = function(value, unit) { + if(typeof value === 'number') { + value = value + unit; + } + + return value; + }; + + /** + * This is a wrapper around document.querySelector that will return the query if it's already of type Node + * + * @memberof Chartist.Core + * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly + * @return {Node} + */ + Chartist.querySelector = function(query) { + return query instanceof Node ? query : document.querySelector(query); + }; + + /** + * Create or reinitialize the SVG element for the chart + * + * @memberof Chartist.Core + * @param {Node} container The containing DOM Node object that will be used to plant the SVG element + * @param {String} width Set the width of the SVG element. Default is 100% + * @param {String} height Set the height of the SVG element. Default is 100% + * @param {String} className Specify a class to be added to the SVG element + * @return {Object} The created/reinitialized SVG element + */ + Chartist.createSvg = function (container, width, height, className) { + var svg; + + width = width || '100%'; + height = height || '100%'; + + svg = container.querySelector('svg'); + if(svg) { + container.removeChild(svg); + } + + // Create svg object with width and height or use 100% as default + svg = new Chartist.Svg('svg').attr({ + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); + + // Add the DOM node to our container + container.appendChild(svg._node); + + return svg; + }; + + /** + * Convert data series into plain array + * + * @memberof Chartist.Core + * @param {Object} data The series object that contains the data to be visualized in the chart + * @return {Array} A plain array that contains the data to be visualized in the chart + */ + Chartist.getDataArray = function (data) { + var array = []; + + for (var i = 0; i < data.series.length; i++) { + // If the series array contains an object with a data property we will use the property + // otherwise the value directly (array or number) + array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? + data.series[i].data : data.series[i]; + + // Convert values to number + for (var j = 0; j < array[i].length; j++) { + array[i][j] = +array[i][j]; + } + } + + return array; + }; + + /** + * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart + * + * @memberof Chartist.Core + * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. + * @param {Number} length The length of the x-axis data array. + * @return {Array} The array that got updated with missing values. + */ + Chartist.normalizeDataArray = function (dataArray, length) { + for (var i = 0; i < dataArray.length; i++) { + if (dataArray[i].length === length) { + continue; + } + + for (var j = dataArray[i].length; j < length; j++) { + dataArray[i][j] = 0; + } + } + + return dataArray; + }; + + /** + * Calculate the order of magnitude for the chart scale + * + * @memberof Chartist.Core + * @param {Number} value The value Range of the chart + * @return {Number} The order of magnitude + */ + Chartist.orderOfMagnitude = function (value) { + return Math.floor(Math.log(Math.abs(value)) / Math.LN10); + }; + + /** + * Project a data length into screen coordinates (pixels) + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Number} length Single data value from a series array + * @param {Object} bounds All the values to set the bounds of the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @return {Number} The projected data length in pixels + */ + Chartist.projectLength = function (svg, length, bounds, options) { + var availableHeight = Chartist.getAvailableHeight(svg, options); + return (length / bounds.range * availableHeight); + }; + + /** + * Get the height of the area in the chart for the data series + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @return {Number} The height of the area in the chart for the data series + */ + Chartist.getAvailableHeight = function (svg, options) { + return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); + }; + + /** + * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. + * + * @memberof Chartist.Core + * @param {Array} dataArray The array that contains the data to be visualized in the chart + * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart. + */ + Chartist.getHighLow = function (dataArray) { + var i, + j, + highLow = { + high: -Number.MAX_VALUE, + low: Number.MAX_VALUE + }; + + for (i = 0; i < dataArray.length; i++) { + for (j = 0; j < dataArray[i].length; j++) { + if (dataArray[i][j] > highLow.high) { + highLow.high = dataArray[i][j]; + } + + if (dataArray[i][j] < highLow.low) { + highLow.low = dataArray[i][j]; + } + } + } + + return highLow; + }; + + // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude + /** + * Calculate and retrieve all the bounds for the chart and return them in one array + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Array} normalizedData The array that got updated with missing values. + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} referenceValue The reference value for the chart. + * @return {Object} All the values to set the bounds of the chart + */ + Chartist.getBounds = function (svg, normalizedData, options, referenceValue) { + var i, + newMin, + newMax, + bounds = Chartist.getHighLow(normalizedData); + + // Overrides of high / low from settings + bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); + bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); + + // If high and low are the same because of misconfiguration or flat data (only the same value) we need + // to set the high or low to 0 depending on the polarity + if(bounds.high === bounds.low) { + // If both values are 0 we set high to 1 + if(bounds.low === 0) { + bounds.high = 1; + } else if(bounds.low < 0) { + // If we have the same negative value for the bounds we set bounds.high to 0 + bounds.high = 0; + } else { + // If we have the same positive value for the bounds we set bounds.low to 0 + bounds.low = 0; + } + } + + // Overrides of high / low based on reference value, it will make sure that the invisible reference value is + // used to generate the chart. This is useful when the chart always needs to contain the position of the + // invisible reference value in the view i.e. for bipolar scales. + if (referenceValue || referenceValue === 0) { + bounds.high = Math.max(referenceValue, bounds.high); + bounds.low = Math.min(referenceValue, bounds.low); + } + + bounds.valueRange = bounds.high - bounds.low; + bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); + bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); + bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); + bounds.range = bounds.max - bounds.min; + bounds.step = Math.pow(10, bounds.oom); + bounds.numberOfSteps = Math.round(bounds.range / bounds.step); + + // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace + // If we are already below the scaleMinSpace value we will scale up + var length = Chartist.projectLength(svg, bounds.step, bounds, options), + scaleUp = length < options.axisY.scaleMinSpace; + + while (true) { + if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { + bounds.step /= 2; + } else { + break; + } + } + + // Narrow min and max based on new step + newMin = bounds.min; + newMax = bounds.max; + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + if (i + bounds.step < bounds.low) { + newMin += bounds.step; + } + + if (i - bounds.step >= bounds.high) { + newMax -= bounds.step; + } + } + bounds.min = newMin; + bounds.max = newMax; + bounds.range = bounds.max - bounds.min; + + bounds.values = []; + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + bounds.values.push(i); + } + + return bounds; + }; + + /** + * Calculate cartesian coordinates of polar coordinates + * + * @memberof Chartist.Core + * @param {Number} centerX X-axis coordinates of center point of circle segment + * @param {Number} centerY X-axis coordinates of center point of circle segment + * @param {Number} radius Radius of circle segment + * @param {Number} angleInDegrees Angle of circle segment in degrees + * @return {Number} Coordinates of point on circumference + */ + Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { + var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; + + return { + x: centerX + (radius * Math.cos(angleInRadians)), + y: centerY + (radius * Math.sin(angleInRadians)) + }; + }; + + /** + * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements + */ + Chartist.createChartRect = function (svg, options) { + var yOffset = options.axisY ? options.axisY.offset : 0, + xOffset = options.axisX ? options.axisX.offset : 0; + + return { + x1: options.chartPadding + yOffset, + y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), + y2: options.chartPadding, + width: function () { + return this.x2 - this.x1; + }, + height: function () { + return this.y1 - this.y2; + } + }; + }; + + /** + * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. + * + * @param {Object} parent The SVG element where the label should be created as a child + * @param {String} text The label text + * @param {Object} attributes An object with all attributes that should be set on the label element + * @param {String} className The class names that should be set for this element + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + * @returns {Object} The newly created SVG element + */ + Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { + if(supportsForeignObject) { + var content = '' + text + ''; + return parent.foreignObject(content, attributes); + } else { + return parent.elem('text', attributes, className).text(text); + } + }; + + /** + * Generate grid lines and labels for the x-axis into grid and labels group SVG elements + * + * @memberof Chartist.Core + * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element + * @param {Object} data The Object that contains the data to be visualized in the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + */ + Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { + // Create X-Axis + data.labels.forEach(function (value, index) { + var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), + width = chartRect.width() / data.labels.length, + height = options.axisX.offset, + pos = chartRect.x1 + width * index; + + // If interpolated value returns falsey (except 0) we don't draw the grid line + if (!interpolatedValue && interpolatedValue !== 0) { + return; + } + + if (options.axisX.showGrid) { + var gridElement = grid.elem('line', { + x1: pos, + y1: chartRect.y1, + x2: pos, + y2: chartRect.y2 + }, [options.classNames.grid, options.classNames.horizontal].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'x', + index: index, + group: grid, + element: gridElement, + x1: pos, + y1: chartRect.y1, + x2: pos, + y2: chartRect.y2 + }); + } + + if (options.axisX.showLabel) { + var labelPosition = { + x: pos + options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) + }; + + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'x', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.width; + } + }); + } + }); + }; + + /** + * Generate grid lines and labels for the y-axis into grid and labels group SVG elements + * + * @memberof Chartist.Core + * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element + * @param {Object} bounds All the values to set the bounds of the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + */ + Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { + // Create Y-Axis + bounds.values.forEach(function (value, index) { + var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), + width = options.axisY.offset, + height = chartRect.height() / bounds.values.length, + pos = chartRect.y1 - height * index; + + // If interpolated value returns falsey (except 0) we don't draw the grid line + if (!interpolatedValue && interpolatedValue !== 0) { + return; + } + + if (options.axisY.showGrid) { + var gridElement = grid.elem('line', { + x1: chartRect.x1, + y1: pos, + x2: chartRect.x2, + y2: pos + }, [options.classNames.grid, options.classNames.vertical].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'y', + index: index, + group: grid, + element: gridElement, + x1: chartRect.x1, + y1: pos, + x2: chartRect.x2, + y2: pos + }); + } + + if (options.axisY.showLabel) { + var labelPosition = { + x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), + y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) + }; + + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'y', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.height; + } + }); + } + }); + }; + + /** + * Determine the current point on the svg element to draw the data series + * + * @memberof Chartist.Core + * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element + * @param {Object} bounds All the values to set the bounds of the chart + * @param {Array} data The array that contains the data to be visualized in the chart + * @param {Number} index The index of the current project point + * @return {Object} The coordinates object of the current project point containing an x and y number property + */ + Chartist.projectPoint = function (chartRect, bounds, data, index) { + return { + x: chartRect.x1 + chartRect.width() / data.length * index, + y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) + }; + }; + + // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one + /** + * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches + * + * @memberof Chartist.Core + * @param {Object} defaultOptions Default options from Chartist + * @param {Object} options Options set by user + * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart + * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events + * @return {Object} The consolidated options object from the defaults, base and matching responsive options + */ + Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions, eventEmitter) { + var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options), + currentOptions, + mediaQueryListeners = [], + i; + + function updateCurrentOptions() { + var previousOptions = currentOptions; + currentOptions = Chartist.extend({}, baseOptions); + + if (responsiveOptions) { + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + if (mql.matches) { + currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]); + } + } + } + + if(eventEmitter) { + eventEmitter.emit('optionsChanged', { + previousOptions: previousOptions, + currentOptions: currentOptions + }); + } + } + + function removeMediaQueryListeners() { + mediaQueryListeners.forEach(function(mql) { + mql.removeListener(updateCurrentOptions); + }); + } + + if (!window.matchMedia) { + throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; + } else if (responsiveOptions) { + + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + mql.addListener(updateCurrentOptions); + mediaQueryListeners.push(mql); + } + } + // Execute initially so we get the correct options + updateCurrentOptions(); + + return { + get currentOptions() { + return Chartist.extend({}, currentOptions); + }, + removeMediaQueryListeners: removeMediaQueryListeners + }; + }; + + //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas + /** + * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property + * where deltas for specific object properties can be found for the given object nesting level. For nested objects the + * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also + * contain a __delta__ property with the deltas of their level. + * + * @param {Object|Array} a Object that should be used to analyzed delta to object b + * @param {Object|Array} b The second object where the deltas from a should be analyzed + * @returns {Object} Delta descriptor object or null + */ + Chartist.deltaDescriptor = function(a, b) { + var summary = { + added: 0, + removed: 0, + modified: 0 + }; + + function findDeltasRecursively(a, b) { + var descriptor = { + __delta__: {} + }; + + // First check for removed and modified properties + Object.keys(a).forEach(function(property) { + if(!b.hasOwnProperty(property)) { + descriptor.__delta__[property] = { + type: 'remove', + property: property, + ours: a[property] + }; + summary.removed++; + } else { + if(typeof a[property] === 'object') { + var subDescriptor = findDeltasRecursively(a[property], b[property]); + if(subDescriptor) { + descriptor[property] = subDescriptor; + } + } else { + if(a[property] !== b[property]) { + descriptor.__delta__[property] = { + type: 'modify', + property: property, + ours: a[property], + theirs: b[property] + }; + summary.modified++; + } + } + } + }); + + // Check for added properties + Object.keys(b).forEach(function(property) { + if(!a.hasOwnProperty(property)) { + descriptor.__delta__[property] = { + type: 'added', + property: property, + theirs: b[property] + }; + summary.added++; + } + }); + + return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null; + } + + var delta = findDeltasRecursively(a, b); + if(delta) { + delta.__delta__.summary = summary; + } + + return delta; + }; + + //http://schepers.cc/getting-to-the-point + Chartist.catmullRom2bezier = function (crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 === i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 === i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push( + [ + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6 * p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ] + ); + } + + return d; + }; + +}(window, document, Chartist)); diff --git a/src/event.js b/src/event.js new file mode 100644 index 00000000..2b495f7b --- /dev/null +++ b/src/event.js @@ -0,0 +1,78 @@ +/** + * A very basic event module that helps to generate and catch events. + * + * @module Chartist.Event + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + Chartist.EventEmitter = function () { + var handlers = []; + + /** + * Add an event handler for a specific event + * + * @memberof Chartist.Event + * @param {String} event The event name + * @param {Function} handler A event handler function + */ + function addEventHandler(event, handler) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + } + + /** + * Remove an event handler of a specific event name or remove all event handlers for a specific event. + * + * @memberof Chartist.Event + * @param {String} event The event name where a specific or all handlers should be removed + * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. + */ + function removeEventHandler(event, handler) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + // If handler is set we will look for a specific handler and only remove this + if(handler) { + handlers[event].splice(handlers[event].indexOf(handler), 1); + if(handlers[event].length === 0) { + delete handlers[event]; + } + } else { + // If no handler is specified we remove all handlers for this event + delete handlers[event]; + } + } + } + + /** + * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. + * + * @memberof Chartist.Event + * @param {String} event The event name that should be triggered + * @param {*} data Arbitrary data that will be passed to the event handler callback functions + */ + function emit(event, data) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + handlers[event].forEach(function(handler) { + handler(data); + }); + } + + // Emit event to star event handlers + if(handlers['*']) { + handlers['*'].forEach(function(starHandler) { + starHandler(event, data); + }); + } + } + + return { + addEventHandler: addEventHandler, + removeEventHandler: removeEventHandler, + emit: emit + }; + }; + +}(window, document, Chartist)); diff --git a/src/styles/_modules.scss b/src/styles/_modules.scss new file mode 100644 index 00000000..938b5eac --- /dev/null +++ b/src/styles/_modules.scss @@ -0,0 +1,5 @@ +@import "http://github.com/modules/common"; +@import "http://github.com/modules/scale"; +@import "http://github.com/modules/animation"; + +// not reuqired, used ? diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss new file mode 100644 index 00000000..1b2f8c43 --- /dev/null +++ b/src/styles/chartist.scss @@ -0,0 +1,152 @@ +@import "http://github.com/modules"; +@import "http://github.com/settings/chartist-settings"; + +@mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) { + display: block; + position: relative; + width: $width; + + &:before { + display: block; + float: left; + content: ""; + width: 0; + height: 0; + padding-bottom: $ratio * 100%; + } + + &:after { + content: ""; + display: table; + clear: both; + } + + > svg { + display: block; + position: absolute; + top: 0; + left: 0; + } +} + +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align) { + display: block; + width: 100%; + height: 100%; + fill: $ct-text-color; + color: $ct-text-color; + font-size: $ct-text-size; + text-align: $ct-text-align; +} + +@mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { + stroke: $ct-grid-color; + stroke-width: $ct-grid-width; + + @if ($ct-grid-dasharray) { + stroke-dasharray: $ct-grid-dasharray; + } +} + +@mixin ct-chart-point($ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape) { + stroke-width: $ct-point-size; + stroke-linecap: $ct-point-shape; +} + +@mixin ct-chart-line($ct-line-width: $ct-line-width, $ct-line-dasharray: $ct-line-dasharray) { + fill: none; + stroke-width: $ct-line-width; + + @if ($ct-line-dasharray) { + stroke-dasharray: $ct-line-dasharray; + } +} + +@mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) { + stroke: none; + fill-opacity: $ct-area-opacity; +} + +@mixin ct-chart-bar($ct-bar-width: $ct-bar-width) { + fill: none; + stroke-width: $ct-bar-width; +} + +@mixin ct-chart-donut($ct-donut-width: $ct-donut-width) { + fill: none; + stroke-width: $ct-donut-width; +} + +@mixin ct-chart-series-color($color) { + .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice}.#{$ct-class-donut} { + stroke: $color; + } + + .#{$ct-class-slice}:not(.#{$ct-class-donut}), .#{$ct-class-area} { + fill: $color; + } +} + +@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { + .#{$ct-class-label} { + @include ct-chart-label($ct-text-color, $ct-text-size); + } + + .#{$ct-class-label}.#{$ct-class-horizontal} { + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align); + } + + .#{$ct-class-label}.#{$ct-class-vertical} { + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align); + } + + .#{$ct-class-grid} { + @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); + } + + .#{$ct-class-point} { + @include ct-chart-point($ct-point-size, $ct-point-shape); + } + + .#{$ct-class-line} { + @include ct-chart-line($ct-line-width); + } + + .#{$ct-class-area} { + @include ct-chart-area(); + } + + .#{$ct-class-bar} { + @include ct-chart-bar($ct-bar-width); + } + + .#{$ct-class-slice}.#{$ct-class-donut} { + @include ct-chart-donut($ct-donut-width); + } + + @if $ct-include-colored-series { + .#{$ct-class-series} { + @for $i from 0 to length($ct-series-names) { + &.#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { + $color: nth($ct-series-colors, $i + 1); + + @include ct-chart-series-color($color); + } + } + } + } +} + +@if $ct-include-classes { + .#{$ct-class-chart} { + @include ct-chart(); + + @if $ct-include-alternative-responsive-containers { + @for $i from 0 to length($ct-scales-names) { + &.#{nth($ct-scales-names, $i + 1)} { + @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); + } + } + } + } +} diff --git a/src/styles/modules/_animation.scss b/src/styles/modules/_animation.scss new file mode 100644 index 00000000..1af626a1 --- /dev/null +++ b/src/styles/modules/_animation.scss @@ -0,0 +1,21 @@ +@mixin keyframes($name) { + @-webkit-keyframes #{$name} { + @content; + } + @-moz-keyframes #{$name} { + @content; + } + @-ms-keyframes #{$name} { + @content; + } + @keyframes #{$name} { + @content; + } +} + +@mixin animation($name, $params) { + -webkit-animation: #{$name} $params; /* Safari 4+ */ + -moz-animation: #{$name} $params; /* Fx 5+ */ + -o-animation: #{$name} $params; /* Opera 12+ */ + animation: #{$name} $params; /* IE 10+ */ +} \ No newline at end of file diff --git a/src/styles/modules/_common.scss b/src/styles/modules/_common.scss new file mode 100644 index 00000000..e29cd020 --- /dev/null +++ b/src/styles/modules/_common.scss @@ -0,0 +1,15 @@ +@function reverse($list, $recursive: false) { + $result: (); + + @for $i from length($list)*-1 through -1 { + @if type-of(nth($list, abs($i))) == list and $recursive { + $result: append($result, reverse(nth($list, abs($i)), $recursive)); + } + + @else { + $result: append($result, nth($list, abs($i))); + } + } + + @return $result; +} \ No newline at end of file diff --git a/src/styles/modules/_scale.scss b/src/styles/modules/_scale.scss new file mode 100644 index 00000000..1a7a3b7d --- /dev/null +++ b/src/styles/modules/_scale.scss @@ -0,0 +1,41 @@ +$scale-minor-second: 15/16; +$scale-major-second: 8/9; +$scale-minor-third: 5/6; +$scale-major-third: 4/5; +$scale-perfect-fourth: 3/4; +$scale-perfect-fifth: 2/3; +$scale-minor-sixth: 5/8; +$scale-golden-section: 1/1.618; +$scale-major-sixth: 3/5; +$scale-minor-seventh: 9/16; +$scale-major-seventh: 8/15; +$scale-octave: 1/2; +$scale-major-tenth: 2/5; +$scale-major-eleventh: 3/8; +$scale-major-twelfth: 1/3; +$scale-double-octave: 1/4; + +@function generateScale($base: 16, $scale-type: $scale-golden-section, $limit-lower: 6, $limit-upper: 100) { + $scale: (); + $value: $base; + + @while $value > $limit-lower { + $value: $value * $scale-type; + @if $value > $limit-lower { + $scale: append($scale, $value); + } + } + + $scale: reverse($scale); + $scale: append($scale, $base); + + $value: $base; + @while $value < $limit-upper { + $value: $value / $scale-type; + @if $value < $limit-upper { + $scale: append($scale, $value); + } + } + + @return $scale; +} \ No newline at end of file diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss new file mode 100644 index 00000000..059e3d8a --- /dev/null +++ b/src/styles/settings/_chartist-settings.scss @@ -0,0 +1,65 @@ +// Scales for responsive SVG containers +$ct-scales: ((1), (15/16), (8/9), (5/6), (4/5), (3/4), (2/3), (5/8), (1/1.618), (3/5), (9/16), (8/15), (1/2), (2/5), (3/8), (1/3), (1/4)) !default; +$ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, ct-major-third, ct-perfect-fourth, ct-perfect-fifth, ct-minor-sixth, ct-golden-section, ct-major-sixth, ct-minor-seventh, ct-major-seventh, ct-octave, ct-major-tenth, ct-major-eleventh, ct-major-twelfth, ct-double-octave) !default; + +// Class names to be used when generating CSS +$ct-class-chart: ct-chart !default; +$ct-class-chart-line: ct-chart-line !default; +$ct-class-chart-bar: ct-chart-bar !default; +$ct-class-chart-pie: ct-chart-pie !default; +$ct-class-label: ct-label !default; +$ct-class-series: ct-series !default; +$ct-class-line: ct-line !default; +$ct-class-point: ct-point !default; +$ct-class-area: ct-area !default; +$ct-class-bar: ct-bar !default; +$ct-class-slice: ct-slice !default; +$ct-class-donut: ct-donut !default; +$ct-class-grid: ct-grid !default; +$ct-class-vertical: ct-vertical !default; +$ct-class-horizontal: ct-horizontal !default; + +// Container ratio +$ct-container-ratio: (1/1.618) !default; + +// Text styles for labels +$ct-text-color: rgba(0, 0, 0, 0.4) !default; +$ct-text-size: 0.75rem !default; +$ct-text-align: left !default; +$ct-horizontal-text-align: left !default; +$ct-vertical-text-align: right !default; + +// Grid styles +$ct-grid-color: rgba(0, 0, 0, 0.2) !default; +$ct-grid-dasharray: 2px !default; +$ct-grid-width: 1px !default; + +// Line chart properties +$ct-line-width: 4px !default; +$ct-line-dasharray: false !default; +$ct-point-size: 10px !default; +// Line chart point, can be either round or square +$ct-point-shape: round !default; +// Area fill transparency between 0 and 1 +$ct-area-opacity: 0.1 !default; + +// Bar chart bar width +$ct-bar-width: 10px !default; + +// Donut width (If donut width is to big it can cause issues where the shape gets distorted) +$ct-donut-width: 60px !default; + +// If set to true it will include the default classes and generate CSS output. If you're planning to use the mixins you +// should set this property to false +$ct-include-classes: true !default; + +// If this is set to true the CSS will contain colored series. You can extend or change the color with the +// properties below +$ct-include-colored-series: $ct-include-classes !default; + +// If set to true this will include all responsive container variations using the scales defined at the top of the script +$ct-include-alternative-responsive-containers: $ct-include-classes !default; + +// Series names and colors. This can be extended or customized as desired. Just add more series and colors. +$ct-series-names: (a, b, c, d) !default; +$ct-series-colors: (#d70206, #F05B4F, #F4C63D, #453D3F) !default; diff --git a/src/svg.js b/src/svg.js new file mode 100644 index 00000000..2e598af5 --- /dev/null +++ b/src/svg.js @@ -0,0 +1,582 @@ +/** + * Chartist SVG module for simple SVG DOM abstraction + * + * @module Chartist.Svg + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + var svgNs = 'http://www.w3.org/2000/svg', + xmlNs = 'http://www.w3.org/2000/xmlns/', + xhtmlNs = 'http://www.w3.org/1999/xhtml'; + + Chartist.xmlNs = { + qualifiedName: 'xmlns:ct', + prefix: 'ct', + uri: 'http://gionkunz.github.com/chartist-js/ct' + }; + + /** + * 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. + * + * @memberof Chartist.Svg + * @constructor + * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg + * @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. + * @param {String} className This class or class list will be added to the SVG element + * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child + * @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 + */ + function Svg(name, attributes, className, parent, insertFirst) { + // If Svg is getting called with an SVG element we just return the wrapper + if(name instanceof SVGElement) { + this._node = name; + } else { + this._node = document.createElementNS(svgNs, name); + + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + } + + if(attributes) { + this.attr(attributes); + } + + if(className) { + this.addClass(className); + } + + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); + } + } + } + } + + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Chartist.Svg + * @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. + * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @returns {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. + */ + function attr(attributes, ns) { + if(typeof attributes === 'string') { + if(ns) { + return this._node.getAttributeNS(ns, attributes); + } else { + return this._node.getAttribute(attributes); + } + } + + Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; + } + + if(ns) { + this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + } else { + this._node.setAttribute(key, attributes[key]); + } + }.bind(this)); + + return this; + } + + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + function elem(name, attributes, className, insertFirst) { + return new Chartist.Svg(name, attributes, className, this, insertFirst); + } + + /** + * Returns the parent Chartist.SVG wrapper object + * + * @returns {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. + */ + function parent() { + return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; + } + + /** + * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. + * + * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element + */ + function root() { + var node = this._node; + while(node.nodeName !== 'svg') { + node = node.parentNode; + } + return new Chartist.Svg(node); + } + + /** + * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found + */ + function querySelector(selector) { + var foundNode = this._node.querySelector(selector); + return foundNode ? new Chartist.Svg(foundNode) : null; + } + + /** + * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found + */ + function querySelectorAll(selector) { + var foundNodes = this._node.querySelectorAll(selector); + return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; + } + + /** + * 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. + * + * @memberof Chartist.Svg + * @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 + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element + */ + function foreignObject(content, attributes, className, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; + } + + // Adding namespace to content element + content.setAttribute('xmlns', xhtmlNs); + + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = this.elem('foreignObject', attributes, className, insertFirst); + + // Add content to foreignObjectElement + fnObj._node.appendChild(content); + + return fnObj; + } + + /** + * This method adds a new text element to the current Chartist.Svg wrapper. + * + * @memberof Chartist.Svg + * @param {String} t The text that should be added to the text element that is created + * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element + */ + function text(t) { + this._node.appendChild(document.createTextNode(t)); + return this; + } + + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Chartist.Svg + * @returns {Chartist.Svg} The same wrapper object that got emptied + */ + function empty() { + while (this._node.firstChild) { + this._node.removeChild(this._node.firstChild); + } + + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg + * @returns {Chartist.Svg} The parent wrapper object of the element that got removed + */ + function remove() { + this._node.parentNode.removeChild(this._node); + return new Chartist.Svg(this._node.parentNode); + } + + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Chartist.Svg + * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object + * @returns {Chartist.Svg} The wrapper of the new element + */ + function replace(newElement) { + this._node.parentNode.replaceChild(newElement._node, this._node); + return newElement; + } + + /** + * This method will append an element to the current element as a child. + * + * @memberof Chartist.Svg + * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @returns {Chartist.Svg} The wrapper of the appended object + */ + function append(element, insertFirst) { + if(insertFirst && this._node.firstChild) { + this._node.insertBefore(element._node, this._node.firstChild); + } else { + this._node.appendChild(element._node); + } + + return this; + } + + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Chartist.Svg + * @returns {Array} A list of classes or an empty array if there are no classes on the current element + */ + function classes() { + return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; + } + + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Chartist.Svg} The wrapper of the current element + */ + function addClass(names) { + this._node.setAttribute('class', + this.classes(this._node) + .concat(names.trim().split(/\s+/)) + .filter(function(elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ') + ); + + return this; + } + + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Chartist.Svg} The wrapper of the current element + */ + function removeClass(names) { + var removedClasses = names.trim().split(/\s+/); + + this._node.setAttribute('class', this.classes(this._node).filter(function(name) { + return removedClasses.indexOf(name) === -1; + }).join(' ')); + + return this; + } + + /** + * Removes all classes from the current element. + * + * @memberof Chartist.Svg + * @returns {Chartist.Svg} The wrapper of the current element + */ + function removeAllClasses() { + this._node.setAttribute('class', ''); + + return this; + } + + /** + * Get element height with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Svg + * @return {Number} The elements height in pixels + */ + function height() { + return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; + } + + /** + * Get element width with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + function width() { + return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + } + + /** + * 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. + * **An animations object could look like this:** + * ```javascript + * element.animate({ + * opacity: { + * dur: 1000, + * from: 0, + * to: 1 + * }, + * x1: { + * dur: '1000ms', + * from: 100, + * to: 200, + * easing: 'easeOutQuart' + * }, + * y1: { + * dur: '2s', + * from: 0, + * to: 100 + * } + * }); + * ``` + * **Automatic unit conversion** + * 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. + * **Guided mode** + * 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. + * If guided mode is enabled the following behavior is added: + * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) + * - The animate element will be forced to use `fill="freeze"` + * - 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. + * - After the animation the element attribute value will be set to the `to` value of the animation + * - The animate element is deleted from the DOM + * + * @memberof Chartist.Svg + * @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. + * @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. + * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. + * @returns {Chartist.Svg} The current element where the animation was added + */ + function animate(animations, guided, eventEmitter) { + if(guided === undefined) { + guided = true; + } + + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + + function createAnimate(animationDefinition, guided) { + var attributeProperties = {}, + animate, + timeout, + easing; + + // Check if an easing is specified in the definition object and delete it from the object as it will not + // be part of the animate element attributes. + if(animationDefinition.easing) { + // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object + easing = animationDefinition.easing instanceof Array ? + animationDefinition.easing : + Chartist.Svg.Easing[animationDefinition.easing]; + delete animationDefinition.easing; + } + + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); + + if(easing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = easing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + + // Adding "fill: freeze" if we are in guided mode and set initial attribute values + if(guided) { + animationDefinition.fill = 'freeze'; + // Animated property on our element should already be set to the animation from value in guided mode + attributeProperties[attribute] = animationDefinition.from; + this.attr(attributeProperties); + + // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin + // which needs to be in ms aside + timeout = Chartist.stripUnit(animationDefinition.begin || 0); + animationDefinition.begin = 'indefinite'; + } + + animate = this.elem('animate', Chartist.extend({ + attributeName: attribute + }, animationDefinition)); + + if(guided) { + // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout + setTimeout(function() { + animate._node.beginElement(); + }, timeout); + } + + if(eventEmitter) { + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animationDefinition + }); + }.bind(this)); + } + + animate._node.addEventListener('endEvent', function handleEndEvent() { + if(eventEmitter) { + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animationDefinition + }); + } + + if(guided) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this)); + } + + // If current attribute is an array of definition objects we create an animate for each and disable guided mode + if(animations[attribute] instanceof Array) { + animations[attribute].forEach(function(animationDefinition) { + createAnimate.bind(this)(animationDefinition, false); + }.bind(this)); + } else { + createAnimate.bind(this)(animations[attribute], guided); + } + + }.bind(this)); + + return this; + } + + Chartist.Svg = Chartist.Class.extend({ + constructor: Svg, + attr: attr, + elem: elem, + parent: parent, + root: root, + querySelector: querySelector, + querySelectorAll: querySelectorAll, + foreignObject: foreignObject, + text: text, + empty: empty, + remove: remove, + replace: replace, + append: append, + classes: classes, + addClass: addClass, + removeClass: removeClass, + removeAllClasses: removeAllClasses, + height: height, + width: width, + animate: animate + }); + + /** + * 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. + * + * @memberof Chartist.Svg + * @param {String} feature The SVG 1.1 feature that should be checked for support. + * @returns {Boolean} True of false if the feature is supported or not + */ + Chartist.Svg.isSupported = function(feature) { + return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); + }; + + /** + * 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. + * + * @memberof Chartist.Svg + */ + var easingCubicBeziers = { + easeInSine: [0.47, 0, 0.745, 0.715], + easeOutSine: [0.39, 0.575, 0.565, 1], + easeInOutSine: [0.445, 0.05, 0.55, 0.95], + easeInQuad: [0.55, 0.085, 0.68, 0.53], + easeOutQuad: [0.25, 0.46, 0.45, 0.94], + easeInOutQuad: [0.455, 0.03, 0.515, 0.955], + easeInCubic: [0.55, 0.055, 0.675, 0.19], + easeOutCubic: [0.215, 0.61, 0.355, 1], + easeInOutCubic: [0.645, 0.045, 0.355, 1], + easeInQuart: [0.895, 0.03, 0.685, 0.22], + easeOutQuart: [0.165, 0.84, 0.44, 1], + easeInOutQuart: [0.77, 0, 0.175, 1], + easeInQuint: [0.755, 0.05, 0.855, 0.06], + easeOutQuint: [0.23, 1, 0.32, 1], + easeInOutQuint: [0.86, 0, 0.07, 1], + easeInExpo: [0.95, 0.05, 0.795, 0.035], + easeOutExpo: [0.19, 1, 0.22, 1], + easeInOutExpo: [1, 0, 0, 1], + easeInCirc: [0.6, 0.04, 0.98, 0.335], + easeOutCirc: [0.075, 0.82, 0.165, 1], + easeInOutCirc: [0.785, 0.135, 0.15, 0.86], + easeInBack: [0.6, -0.28, 0.735, 0.045], + easeOutBack: [0.175, 0.885, 0.32, 1.275], + easeInOutBack: [0.68, -0.55, 0.265, 1.55] + }; + + Chartist.Svg.Easing = easingCubicBeziers; + + /** + * 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. + * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. + * + * @memberof Chartist.Svg + * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) + * @constructor + */ + function SvgList(nodeList) { + var list = this; + + this.svgElements = []; + for(var i = 0; i < nodeList.length; i++) { + this.svgElements.push(new Chartist.Svg(nodeList[i])); + } + + // Add delegation methods for Chartist.Svg + Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { + return ['constructor', + 'parent', + 'querySelector', + 'querySelectorAll', + 'replace', + 'append', + 'classes', + 'height', + 'width'].indexOf(prototypeProperty) === -1; + }).forEach(function(prototypeProperty) { + list[prototypeProperty] = function() { + var args = Array.prototype.slice.call(arguments, 0); + list.svgElements.forEach(function(element) { + Chartist.Svg.prototype[prototypeProperty].apply(element, args); + }); + return list; + }; + }); + } + + Chartist.Svg.List = Chartist.Class.extend({ + constructor: SvgList + }); + +}(window, document, Chartist)); diff --git a/src/types/bar.js b/src/types/bar.js new file mode 100644 index 00000000..04525a06 --- /dev/null +++ b/src/types/bar.js @@ -0,0 +1,248 @@ +/** + * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. + * + * @module Chartist.Bar + */ +/* global Chartist */ +(function(window, document, Chartist){ + 'use strict'; + + var defaultOptions = { + axisX: { + offset: 30, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 40, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 20 + }, + width: undefined, + height: undefined, + high: undefined, + low: undefined, + chartPadding: 5, + seriesBarDistance: 15, + classNames: { + chart: 'ct-chart-bar', + label: 'ct-label', + labelGroup: 'ct-labels', + series: 'ct-series', + bar: 'ct-bar', + grid: 'ct-grid', + gridGroup: 'ct-grids', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg element + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); + + var chartRect = Chartist.createChartRect(this.svg, options); + // Start drawing + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup), + // Projected 0 point + zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. + var biPol = i - (this.data.series.length - 1) / 2, + // Half of the period with between vertical grid lines used to position bars + periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; + + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + for(var j = 0; j < normalizedData[i].length; j++) { + var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), + bar; + + // Offset to center bar between grid lines and using bi-polar offset for multiple series + // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors + p.x += periodHalfWidth + (biPol * options.seriesBarDistance); + + bar = seriesGroups[i].elem('line', { + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }, options.classNames.bar).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'bar', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: bar, + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }); + } + } + + this.eventEmitter.emit('created', { + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options + }); + } + + /** + * This method creates a new bar chart and returns API object that you can use for later changes. + * + * @memberof Chartist.Bar + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // These are the default options of the bar chart + * var options = { + * // Options for X-Axis + * axisX: { + * // The offset of the chart drawing area to the border of the container + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;} + * }, + * // Options for Y-Axis + * axisY: { + * // The offset of the chart drawing area to the border of the container + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;}, + * // This value specifies the minimum height in pixel of the scale steps + * scaleMinSpace: 30 + * }, + * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + * width: undefined, + * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + * height: undefined, + * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + * low: undefined, + * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + * high: undefined, + * // Padding of the chart drawing area to the container element and labels + * chartPadding: 5, + * // Specify the distance in pixel of bars in a group + * seriesBarDistance: 15, + * // Override the class names that get used to generate the SVG structure of the chart + * classNames: { + * chart: 'ct-chart-bar', + * label: 'ct-label', + * labelGroup: 'ct-labels', + * series: 'ct-series', + * bar: 'ct-bar', + * grid: 'ct-grid', + * gridGroup: 'ct-grids', + * vertical: 'ct-vertical', + * horizontal: 'ct-horizontal' + * } + * }; + * + * @example + * // Create a simple bar chart + * var data = { + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // 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. + * new Chartist.Bar('.ct-chart', data); + * + * @example + * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 + * new Chartist.Bar('.ct-chart', { + * labels: [1, 2, 3, 4, 5, 6, 7], + * series: [ + * [1, 3, 2, -5, -3, 1, -6], + * [-5, -2, -4, -1, 2, -3, 1] + * ] + * }, { + * seriesBarDistance: 12, + * low: -10, + * high: 10 + * }); + * + */ + function Bar(query, data, options, responsiveOptions) { + Chartist.Bar.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } + + // Creating bar chart type in Chartist namespace + Chartist.Bar = Chartist.Base.extend({ + constructor: Bar, + createChart: createChart + }); + +}(window, document, Chartist)); diff --git a/src/types/line.js b/src/types/line.js new file mode 100644 index 00000000..aea42aa6 --- /dev/null +++ b/src/types/line.js @@ -0,0 +1,357 @@ +/** + * 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. + * + * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. + * + * @module Chartist.Line + */ +/* global Chartist */ +(function(window, document, Chartist){ + 'use strict'; + + var defaultOptions = { + axisX: { + offset: 30, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 40, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 20 + }, + width: undefined, + height: undefined, + showLine: true, + showPoint: true, + showArea: false, + areaBase: 0, + lineSmooth: true, + low: undefined, + high: undefined, + chartPadding: 5, + 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', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg object + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options); + + var chartRect = Chartist.createChartRect(this.svg, options); + // Start drawing + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var p, + pathCoordinates = [], + point; + + for (var j = 0; j < normalizedData[i].length; j++) { + p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); + pathCoordinates.push(p.x, p.y); + + //If we should show points we need to create them now to avoid secondary loop + // Small offset for Firefox to render squares correctly + if (options.showPoint) { + point = seriesGroups[i].elem('line', { + x1: p.x, + y1: p.y, + x2: p.x + 0.01, + y2: p.y + }, options.classNames.point).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'point', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: point, + x: p.x, + y: p.y + }); + } + } + + // TODO: Nicer handling of conditions, maybe composition? + if (options.showLine || options.showArea) { + // TODO: We should add a path API in the SVG library for easier path creation + var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; + + // If smoothed path and path has more than two points then use catmull rom to bezier algorithm + if (options.lineSmooth && pathCoordinates.length > 4) { + + var cr = Chartist.catmullRom2bezier(pathCoordinates); + for(var k = 0; k < cr.length; k++) { + pathElements.push('C' + cr[k].join()); + } + } else { + for(var l = 3; l < pathCoordinates.length; l += 2) { + pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); + } + } + + if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); + + // If we need to draw area shapes we just make a copy of our pathElements SVG path array + var areaPathElements = pathElements.slice(); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); + // And splice our new area path array to add the missing path elements to close the area shape + areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); + areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; + areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + + // Create the new path for the area shape with the area class from the options + var area = seriesGroups[i].elem('path', { + d: areaPathElements.join('') + }, options.classNames.area, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: area + }); + } + + if(options.showLine) { + var line = seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: line + }); + } + } + } + + this.eventEmitter.emit('created', { + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options + }); + } + + /** + * This method creates a new line chart. + * + * @memberof Chartist.Line + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // These are the default options of the line chart + * var options = { + * // Options for X-Axis + * axisX: { + * // The offset of the labels to the chart area + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;} + * }, + * // Options for Y-Axis + * axisY: { + * // The offset of the labels to the chart area + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;}, + * // This value specifies the minimum height in pixel of the scale steps + * scaleMinSpace: 30 + * }, + * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + * width: undefined, + * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + * height: undefined, + * // If the line should be drawn or not + * showLine: true, + * // If dots should be drawn or not + * showPoint: true, + * // If the line chart should draw an area + * showArea: false, + * // The base for the area chart that will be used to close the area shape (is normally 0) + * areaBase: 0, + * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) + * lineSmooth: true, + * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + * low: undefined, + * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + * high: undefined, + * // Padding of the chart drawing area to the container element and labels + * chartPadding: 5, + * // Override the class names that get used to generate the SVG structure of the chart + * 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', + * vertical: 'ct-vertical', + * horizontal: 'ct-horizontal' + * } + * }; + * + * @example + * // Create a simple line chart + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // As options we currently only set a static size of 300x200 px + * var options = { + * width: '300px', + * height: '200px' + * }; + * + * // 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 + * new Chartist.Line('.ct-chart', data, options); + * + * @example + * // Create a line chart with responsive options + * + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. + * var responsiveOptions = [ + * ['screen and (min-width: 641px) and (max-width: 1024px)', { + * showPoint: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return Mon, Tue, Wed etc. on medium screens + * return value.slice(0, 3); + * } + * } + * }], + * ['screen and (max-width: 640px)', { + * showLine: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return M, T, W etc. on small screens + * return value[0]; + * } + * } + * }] + * ]; + * + * new Chartist.Line('.ct-chart', data, null, responsiveOptions); + * + */ + function Line(query, data, options, responsiveOptions) { + Chartist.Line.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } + + // Creating line chart type in Chartist namespace + Chartist.Line = Chartist.Base.extend({ + constructor: Line, + createChart: createChart + }); + +}(window, document, Chartist)); diff --git a/src/types/pie.js b/src/types/pie.js new file mode 100644 index 00000000..2edf763d --- /dev/null +++ b/src/types/pie.js @@ -0,0 +1,291 @@ +/** + * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts + * + * @module Chartist.Pie + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + var defaultOptions = { + width: undefined, + height: undefined, + chartPadding: 5, + classNames: { + chart: 'ct-chart-pie', + series: 'ct-series', + slice: 'ct-slice', + donut: 'ct-donut', + label: 'ct-label' + }, + startAngle: 0, + total: undefined, + donut: false, + donutWidth: 60, + showLabel: true, + labelOffset: 0, + labelInterpolationFnc: Chartist.noop, + labelOverflow: false, + labelDirection: 'neutral' + }; + + function determineAnchorPosition(center, label, direction) { + var toTheRight = label.x > center.x; + + if(toTheRight && direction === 'explode' || + !toTheRight && direction === 'implode') { + return 'start'; + } else if(toTheRight && direction === 'implode' || + !toTheRight && direction === 'explode') { + return 'end'; + } else { + return 'middle'; + } + } + + function createChart(options) { + var seriesGroups = [], + chartRect, + radius, + labelRadius, + totalDataSum, + startAngle = options.startAngle, + dataArray = Chartist.getDataArray(this.data); + + // Create SVG.js draw + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + // Calculate charting rect + chartRect = Chartist.createChartRect(this.svg, options, 0, 0); + // Get biggest circle radius possible within chartRect + radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + // Calculate total of all series to get reference value or use total reference from optional options + totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { + return previousValue + currentValue; + }, 0); + + // 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 ? options.donutWidth / 2 : 0; + + // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius + // see https://github.com/gionkunz/chartist-js/issues/21 + labelRadius = options.donut ? radius : radius / 2; + // Add the offset to the labelRadius where a negative offset means closed to the center of the chart + labelRadius += options.labelOffset; + + // Calculate end angle based on total sum and current data value and offset with padding + var center = { + x: chartRect.x1 + chartRect.width() / 2, + y: chartRect.y2 + chartRect.height() / 2 + }; + + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = this.data.series.filter(function(val) { + return val !== 0; + }).length === 1; + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g', null, null, true); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle + // with Z and use 359.99 degrees + if(endAngle - startAngle === 360) { + endAngle -= 0.01; + } + + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), + arcSweep = endAngle - startAngle <= 180 ? '0' : '1', + d = [ + // Start at the end point from the cartesian coordinates + 'M', end.x, end.y, + // Draw arc + 'A', radius, radius, 0, arcSweep, 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 === false) { + d.push('L', center.x, center.y); + } + + // Create the SVG path + // If this is a donut chart we add the donut class, otherwise just a regular slice + var path = seriesGroups[i].elem('path', { + d: d.join(' ') + }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); + + // Adding the pie series value to the path + path.attr({ + 'value': dataArray[i] + }, Chartist.xmlNs.uri); + + // If this is a donut, we add the stroke-width as style attribute + if(options.donut === true) { + path.attr({ + 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' + }); + } + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'slice', + value: dataArray[i], + totalDataSum: totalDataSum, + index: i, + group: seriesGroups[i], + element: path, + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + + // If we need to show labels we need to add the label for this slice now + if(options.showLabel) { + // Position at the labelRadius distance from center and between start and end angle + var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), + interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + + var labelElement = seriesGroups[i].elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } + + // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // (except for last slice) + startAngle = endAngle; + } + + this.eventEmitter.emit('created', { + chartRect: chartRect, + svg: this.svg, + options: options + }); + } + + /** + * This method creates a new pie chart and returns an object that can be used to redraw the chart. + * + * @memberof Chartist.Pie + * @param {String|Node} query A selector query string or directly a DOM element + * @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. + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object with a version and an update method to manually redraw the chart + * + * @example + * // Default options of the pie chart + * var defaultOptions = { + * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + * width: undefined, + * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + * height: undefined, + * // Padding of the chart drawing area to the container element and labels + * chartPadding: 5, + * // Override the class names that get used to generate the SVG structure of the chart + * classNames: { + * chart: 'ct-chart-pie', + * series: 'ct-series', + * slice: 'ct-slice', + * donut: 'ct-donut', + label: 'ct-label' + * }, + * // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. + * startAngle: 0, + * // 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. + * total: undefined, + * // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. + * donut: false, + * // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. + * donutWidth: 60, + * // If a label should be shown or not + * showLabel: true, + * // 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. + * labelOffset: 0, + * // An interpolation function for the label value + * labelInterpolationFnc: function(value, index) {return value;}, + * // 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. + * labelDirection: 'neutral' + * }; + * + * @example + * // Simple pie chart example with four series + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }); + * + * @example + * // Drawing a donut chart + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }, { + * donut: true + * }); + * + * @example + * // Using donut, startAngle and total to draw a gauge chart + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * donut: true, + * donutWidth: 20, + * startAngle: 270, + * total: 200 + * }); + * + * @example + * // Drawing a pie chart with padding and labels that are outside the pie + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * chartPadding: 30, + * labelOffset: 50, + * labelDirection: 'explode' + * }); + */ + function Pie(query, data, options, responsiveOptions) { + Chartist.Pie.super.constructor.call(this, + query, + data, + Chartist.extend(Chartist.extend({}, defaultOptions), options), + responsiveOptions); + } + + // Creating pie chart type in Chartist namespace + Chartist.Pie = Chartist.Base.extend({ + constructor: Pie, + createChart: createChart, + determineAnchorPosition: determineAnchorPosition + }); + +}(window, document, Chartist)); From 5466fa3c7607a737e34fa876ad756355743200a3 Mon Sep 17 00:00:00 2001 From: Autarc Date: Tue, 25 Nov 2014 09:51:01 +0100 Subject: [PATCH 094/593] rename compiled files --- {libdist => dist}/LICENSE | 0 {libdist => dist}/chartist.js | 32 +++++++++++-------- {libdist => dist}/chartist.min.css | 0 dist/chartist.min.js | 8 +++++ dist/chartist.min.js.map | 1 + {libdist => dist}/scss/_modules.scss | 2 ++ {libdist => dist}/scss/chartist.scss | 2 +- .../scss/modules/_animation.scss | 0 {libdist => dist}/scss/modules/_common.scss | 0 {libdist => dist}/scss/modules/_scale.scss | 0 .../scss/settings/_chartist-settings.scss | 0 libdist/chartist.min.js | 8 ----- libdist/chartist.min.map | 1 - 13 files changed, 31 insertions(+), 23 deletions(-) rename {libdist => dist}/LICENSE (100%) rename {libdist => dist}/chartist.js (99%) rename {libdist => dist}/chartist.min.css (100%) create mode 100644 dist/chartist.min.js create mode 100644 dist/chartist.min.js.map rename {libdist => dist}/scss/_modules.scss (76%) rename {libdist => dist}/scss/chartist.scss (99%) rename {libdist => dist}/scss/modules/_animation.scss (100%) rename {libdist => dist}/scss/modules/_common.scss (100%) rename {libdist => dist}/scss/modules/_scale.scss (100%) rename {libdist => dist}/scss/settings/_chartist-settings.scss (100%) delete mode 100644 libdist/chartist.min.js delete mode 100644 libdist/chartist.min.map diff --git a/libdist/LICENSE b/dist/LICENSE similarity index 100% rename from libdist/LICENSE rename to dist/LICENSE diff --git a/libdist/chartist.js b/dist/chartist.js similarity index 99% rename from libdist/chartist.js rename to dist/chartist.js index e610dc67..f3755aad 100644 --- a/libdist/chartist.js +++ b/dist/chartist.js @@ -1,14 +1,18 @@ -(function(root, factory) { - if(typeof exports === 'object') { - module.exports = factory(); - } - else if(typeof define === 'function' && define.amd) { - define([], factory); - } - else { - root['Chartist'] = factory(); - } -}(this, function() { +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], function () { + return (root.returnExportsGlobal = factory()); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like enviroments that support module.exports, + // like Node. + module.exports = factory(); + } else { + root['Chartist'] = factory(); + } +}(this, function () { /* Chartist.js 0.4.1 * Copyright © 2014 Gion Kunz @@ -20,8 +24,9 @@ * * @module Chartist.Core */ - var Chartist = {}; - Chartist.version = '0.3.1'; + var Chartist = { + version: '0.4.1' + }; (function (window, document, Chartist) { 'use strict'; @@ -2679,4 +2684,5 @@ return Chartist; + })); diff --git a/libdist/chartist.min.css b/dist/chartist.min.css similarity index 100% rename from libdist/chartist.min.css rename to dist/chartist.min.css diff --git a/dist/chartist.min.js b/dist/chartist.min.js new file mode 100644 index 00000000..06403e61 --- /dev/null +++ b/dist/chartist.min.js @@ -0,0 +1,8 @@ +/* Chartist.js 0.4.1 + * Copyright © 2014 Gion Kunz + * Free to use under the WTFPL license. + * http://www.wtfpl.net/ + */ + +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;j0?e:null}var d={added:0,removed:0,modified:0},e=c(a,b);return e&&(e.__delta__.summary=d),e},c.catmullRom2bezier=function(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map new file mode 100644 index 00000000..ab2ba278 --- /dev/null +++ b/dist/chartist.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18979,"pos":18974,"col":16,"line":498,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18979,"pos":18974,"col":16,"line":498,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","deltaDescriptor","a","b","findDeltasRecursively","descriptor","__delta__","Object","keys","property","hasOwnProperty","subDescriptor","ours","theirs","summary","modified","removed","added","delta","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":";;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,UAAW,WACT,MAAQF,GAAKI,oBAAsBH,MAET,gBAAZI,SAIhBC,OAAOD,QAAUJ,IAEjBD,EAAe,SAAIC,KAErBM,KAAM,WAYN,GAAIC,IACFC,QAAS,QAimFX,OA9lFC,UAAUC,EAAQC,EAAUH,GAC3B,YASAA,GAASI,KAAO,SAAUC,GACxB,MAAOA,IAUTL,EAASM,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAYtCL,EAASS,OAAS,SAAUC,EAAQC,GAClCD,EAASA,KACT,KAAK,GAAIE,KAAQD,GAEbD,EAAOE,GADmB,gBAAjBD,GAAOC,GACDZ,EAASS,OAAOC,EAAOE,GAAOD,EAAOC,IAErCD,EAAOC,EAG1B,OAAOF,IAUTV,EAASa,UAAY,SAASC,GAK5B,MAJoB,gBAAVA,KACRA,EAAQA,EAAMC,QAAQ,eAAgB,MAGhCD,GAWVd,EAASgB,WAAa,SAASF,EAAOG,GAKpC,MAJoB,gBAAVH,KACRA,GAAgBG,GAGXH,GAUTd,EAASkB,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQhB,EAASe,cAAcC,IAahEnB,EAASqB,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIC,EAqBJ,OAnBAH,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAEnBE,EAAMJ,EAAUJ,cAAc,OAC3BQ,GACDJ,EAAUK,YAAYD,GAIxBA,EAAM,GAAI1B,GAAS4B,IAAI,OAAOC,MAC5BN,MAAOA,EACPC,OAAQA,IACPM,SAASL,GAAWI,MACrBE,MAAO,UAAYR,EAAQ,aAAeC,EAAS,MAIrDF,EAAUU,YAAYN,EAAIO,OAEnBP,GAUT1B,EAASkC,aAAe,SAAUC,GAGhC,IAAK,GAFDC,MAEKC,EAAI,EAAGA,EAAIF,EAAKG,OAAOC,OAAQF,IAAK,CAG3CD,EAAMC,GAAgC,gBAApBF,GAAKG,OAAOD,IAA4CG,SAAxBL,EAAKG,OAAOD,GAAGF,KAC/DA,EAAKG,OAAOD,GAAGF,KAAOA,EAAKG,OAAOD,EAGpC,KAAK,GAAII,GAAI,EAAGA,EAAIL,EAAMC,GAAGE,OAAQE,IACnCL,EAAMC,GAAGI,IAAML,EAAMC,GAAGI,GAI5B,MAAOL,IAWTpC,EAAS0C,mBAAqB,SAAUC,EAAWJ,GACjD,IAAK,GAAIF,GAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IACpC,GAAIM,EAAUN,GAAGE,SAAWA,EAI5B,IAAK,GAAIE,GAAIE,EAAUN,GAAGE,OAAYA,EAAJE,EAAYA,IAC5CE,EAAUN,GAAGI,GAAK,CAItB,OAAOE,IAUT3C,EAAS4C,iBAAmB,SAAU9B,GACpC,MAAO+B,MAAKC,MAAMD,KAAKE,IAAIF,KAAKG,IAAIlC,IAAU+B,KAAKI,OAarDjD,EAASkD,cAAgB,SAAUxB,EAAKa,EAAQY,EAAQC,GACtD,GAAIC,GAAkBrD,EAASsD,mBAAmB5B,EAAK0B,EACvD,OAAQb,GAASY,EAAOI,MAAQF,GAWlCrD,EAASsD,mBAAqB,SAAU5B,EAAK0B,GAC3C,MAAOP,MAAKW,KAAKxD,EAASa,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAoC,EAAvB4B,EAAQK,aAAoBL,EAAQM,MAAMC,OAAQ,IAU5H3D,EAAS4D,WAAa,SAAUjB,GAC9B,GAAIN,GACFI,EACAoB,GACEC,MAAOC,OAAOC,UACdC,IAAKF,OAAOC,UAGhB,KAAK3B,EAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IAChC,IAAKI,EAAI,EAAGA,EAAIE,EAAUN,GAAGE,OAAQE,IAC/BE,EAAUN,GAAGI,GAAKoB,EAAQC,OAC5BD,EAAQC,KAAOnB,EAAUN,GAAGI,IAG1BE,EAAUN,GAAGI,GAAKoB,EAAQI,MAC5BJ,EAAQI,IAAMtB,EAAUN,GAAGI,GAKjC,OAAOoB,IAcT7D,EAASkE,UAAY,SAAUxC,EAAKyC,EAAgBf,EAASgB,GAC3D,GAAI/B,GACFgC,EACAC,EACAnB,EAASnD,EAAS4D,WAAWO,EAG/BhB,GAAOW,MAAQV,EAAQU,OAA0B,IAAjBV,EAAQU,KAAa,EAAIX,EAAOW,MAChEX,EAAOc,KAAOb,EAAQa,MAAwB,IAAhBb,EAAQa,IAAY,EAAId,EAAOc,KAI1Dd,EAAOW,OAASX,EAAOc,MAEN,IAAfd,EAAOc,IACRd,EAAOW,KAAO,EACNX,EAAOc,IAAM,EAErBd,EAAOW,KAAO,EAGdX,EAAOc,IAAM,IAObG,GAAqC,IAAnBA,KACpBjB,EAAOW,KAAOjB,KAAKW,IAAIY,EAAgBjB,EAAOW,MAC9CX,EAAOc,IAAMpB,KAAK0B,IAAIH,EAAgBjB,EAAOc,MAG/Cd,EAAOqB,WAAarB,EAAOW,KAAOX,EAAOc,IACzCd,EAAOsB,IAAMzE,EAAS4C,iBAAiBO,EAAOqB,YAC9CrB,EAAOoB,IAAM1B,KAAKC,MAAMK,EAAOc,IAAMpB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOK,IAAMX,KAAK8B,KAAKxB,EAAOW,KAAOjB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IACnCpB,EAAOyB,KAAO/B,KAAK6B,IAAI,GAAIvB,EAAOsB,KAClCtB,EAAO0B,cAAgBhC,KAAKiC,MAAM3B,EAAOI,MAAQJ,EAAOyB,KAOxD,KAHA,GAAIrC,GAASvC,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,GAC5D2B,EAAUxC,EAASa,EAAQ4B,MAAMC,gBAGjC,GAAIF,GAAW/E,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,IAAYA,EAAQ4B,MAAMC,cACxF9B,EAAOyB,MAAQ,MACV,CAAA,GAAKG,KAAW/E,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAO,EAAGzB,EAAQC,IAAYA,EAAQ4B,MAAMC,eAGpG,KAFA9B,GAAOyB,MAAQ,EASnB,IAFAP,EAASlB,EAAOoB,IAChBD,EAASnB,EAAOK,IACXnB,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAC5CvC,EAAIc,EAAOyB,KAAOzB,EAAOc,MAC3BI,GAAUlB,EAAOyB,MAGfvC,EAAIc,EAAOyB,MAAQzB,EAAOW,OAC5BQ,GAAUnB,EAAOyB,KAQrB,KALAzB,EAAOoB,IAAMF,EACblB,EAAOK,IAAMc,EACbnB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IAEnCpB,EAAO+B,UACF7C,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAChDzB,EAAO+B,OAAOC,KAAK9C,EAGrB,OAAOc,IAaTnD,EAASoF,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAM3C,KAAK6C,GAAK,GAEvD,QACEC,EAAGN,EAAWE,EAAS1C,KAAK+C,IAAIH,GAChCI,EAAGP,EAAWC,EAAS1C,KAAKiD,IAAIL,KAYpCzF,EAAS+F,gBAAkB,SAAUrE,EAAK0B,GACxC,GAAI4C,GAAU5C,EAAQ4B,MAAQ5B,EAAQ4B,MAAMrB,OAAS,EACnDsC,EAAU7C,EAAQM,MAAQN,EAAQM,MAAMC,OAAS,CAEnD,QACEuC,GAAI9C,EAAQK,aAAeuC,EAC3BG,GAAItD,KAAKW,KAAKxD,EAASa,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAY4B,EAAQK,aAAewC,EAAS7C,EAAQK,cAC5G2C,GAAIvD,KAAKW,KAAKxD,EAASa,UAAUuC,EAAQ7B,QAAUG,EAAIH,SAAW6B,EAAQK,aAAcL,EAAQK,aAAeuC,GAC/GK,GAAIjD,EAAQK,aACZlC,MAAO,WACL,MAAOxB,MAAKqG,GAAKrG,KAAKmG,IAExB1E,OAAQ,WACN,MAAOzB,MAAKoG,GAAKpG,KAAKsG,MAe5BrG,EAASsG,YAAc,SAASC,EAAQC,EAAMC,EAAYhF,EAAWiF,GACnE,GAAGA,EAAuB,CACxB,GAAIC,GAAU,gBAAkBlF,EAAY,KAAO+E,EAAO,SAC1D,OAAOD,GAAOK,cAAcD,EAASF,GAErC,MAAOF,GAAOM,KAAK,OAAQJ,EAAYhF,GAAW+E,KAAKA,IAgB3DxG,EAAS8G,YAAc,SAAUC,EAAW5E,EAAM6E,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAErFvE,EAAK8E,OAAOE,QAAQ,SAAUrG,EAAOsG,GACnC,GAAIC,GAAoBjE,EAAQM,MAAM4D,sBAAsBxG,EAAOsG,GACjE7F,EAAQwF,EAAUxF,QAAUY,EAAK8E,OAAO1E,OACxCf,EAAS4B,EAAQM,MAAMC,OACvB4D,EAAMR,EAAUb,GAAK3E,EAAQ6F,CAG/B,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIjE,EAAQM,MAAM8D,SAAU,CAC1B,GAAIC,GAAcT,EAAKH,KAAK,QAC1BX,GAAIqB,EACJpB,GAAIY,EAAUZ,GACdC,GAAImB,EACJlB,GAAIU,EAAUV,KACZjD,EAAQsE,WAAWV,KAAM5D,EAAQsE,WAAWC,YAAYC,KAAK,KAGjEV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTvB,GAAIqB,EACJpB,GAAIY,EAAUZ,GACdC,GAAImB,EACJlB,GAAIU,EAAUV,KAIlB,GAAIjD,EAAQM,MAAMwE,UAAW,CAC3B,GAAIC,IACFxC,EAAG4B,EAAMnE,EAAQM,MAAM0E,YAAYzC,EACnCE,EAAGkB,EAAUZ,GAAK/C,EAAQM,MAAM0E,YAAYvC,GAAKa,EAAwB,EAAI,KAG3E2B,EAAerI,EAASsG,YAAYW,EAAQ,GAAKI,GACnD1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQsE,WAAWY,MAAOlF,EAAQsE,WAAWC,YAAYC,KAAK,KAAMlB,EAExEQ,GAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EAER+G,GAAIC,SAEF,MADAtI,GAAOuI,QAAQC,KAAK,mEACb3I,KAAKwB,cAmBtBvB,EAAS2I,YAAc,SAAU5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAEvFvD,EAAO+B,OAAOiC,QAAQ,SAAUrG,EAAOsG,GACrC,GAAIC,GAAoBjE,EAAQ4B,MAAMsC,sBAAsBxG,EAAOsG,GACjE7F,EAAQ6B,EAAQ4B,MAAMrB,OACtBnC,EAASuF,EAAUvF,SAAW2B,EAAO+B,OAAO3C,OAC5CgF,EAAMR,EAAUZ,GAAK3E,EAAS4F,CAGhC,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIjE,EAAQ4B,MAAMwC,SAAU,CAC1B,GAAIC,GAAcT,EAAKH,KAAK,QAC1BX,GAAIa,EAAUb,GACdC,GAAIoB,EACJnB,GAAIW,EAAUX,GACdC,GAAIkB,IACFnE,EAAQsE,WAAWV,KAAM5D,EAAQsE,WAAWkB,UAAUhB,KAAK,KAG/DV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTvB,GAAIa,EAAUb,GACdC,GAAIoB,EACJnB,GAAIW,EAAUX,GACdC,GAAIkB,IAIR,GAAInE,EAAQ4B,MAAMkD,UAAW,CAC3B,GAAIC,IACFxC,EAAGvC,EAAQK,aAAeL,EAAQ4B,MAAMoD,YAAYzC,GAAKe,EAAwB,IAAM,GACvFb,EAAG0B,EAAMnE,EAAQ4B,MAAMoD,YAAYvC,GAAKa,EAAwB,IAAM,IAGpE2B,EAAerI,EAASsG,YAAYW,EAAQ,GAAKI,GACnD1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQsE,WAAWY,MAAOlF,EAAQsE,WAAWkB,UAAUhB,KAAK,KAAMlB,EAEtEQ,GAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EAER+G,GAAIC,SAEF,MADAtI,GAAOuI,QAAQC,KAAK,mEACb3I,KAAKyB,eAiBtBxB,EAAS6I,aAAe,SAAU9B,EAAW5D,EAAQhB,EAAMiF,GACzD,OACEzB,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAUY,EAAKI,OAAS6E,EACpDvB,EAAGkB,EAAUZ,GAAKY,EAAUvF,UAAYW,EAAKiF,GAASjE,EAAOoB,MAAQpB,EAAOI,MAAQJ,EAAOyB,QAe/F5E,EAAS8I,gBAAkB,SAAUC,EAAgB3F,EAAS4F,EAAmB9B,GAM/E,QAAS+B,KACP,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiBnJ,EAASS,UAAW2I,GAEjCJ,EACF,IAAK3G,EAAI,EAAGA,EAAI2G,EAAkBzG,OAAQF,IAAK,CAC7C,GAAIgH,GAAMnJ,EAAOoJ,WAAWN,EAAkB3G,GAAG,GAC7CgH,GAAIE,UACNJ,EAAiBnJ,EAASS,OAAO0I,EAAgBH,EAAkB3G,GAAG,KAKzE6E,GACDA,EAAaW,KAAK,kBAChBqB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoBtC,QAAQ,SAASkC,GACnCA,EAAIK,eAAeT,KA5BvB,GACEE,GAEA9G,EAHE+G,EAAcpJ,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GAErEqG,IA8BF,KAAKvJ,EAAOoJ,WACV,KAAM,iEACD,IAAIN,EAET,IAAK3G,EAAI,EAAGA,EAAI2G,EAAkBzG,OAAQF,IAAK,CAC7C,GAAIgH,GAAMnJ,EAAOoJ,WAAWN,EAAkB3G,GAAG,GACjDgH,GAAIM,YAAYV,GAChBQ,EAAoBtE,KAAKkE,GAM7B,MAFAJ,MAGEV,GAAIY,kBACF,MAAOnJ,GAASS,UAAW0I,IAE7BK,0BAA2BA,IAe/BxJ,EAAS4J,gBAAkB,SAASC,EAAGC,GAOrC,QAASC,GAAsBF,EAAGC,GAChC,GAAIE,IACFC,aA4CF,OAxCAC,QAAOC,KAAKN,GAAG1C,QAAQ,SAASiD,GAC9B,GAAIN,EAAEO,eAAeD,GAQnB,GAA0B,gBAAhBP,GAAEO,GAAwB,CAClC,GAAIE,GAAgBP,EAAsBF,EAAEO,GAAWN,EAAEM,GACtDE,KACDN,EAAWI,GAAYE,OAGtBT,GAAEO,KAAcN,EAAEM,KACnBJ,EAAWC,UAAUG,IACnBtC,KAAM,SACNsC,SAAUA,EACVG,KAAMV,EAAEO,GACRI,OAAQV,EAAEM,IAEZK,EAAQC,gBApBZV,GAAWC,UAAUG,IACnBtC,KAAM,SACNsC,SAAUA,EACVG,KAAMV,EAAEO,IAEVK,EAAQE,YAsBZT,OAAOC,KAAKL,GAAG3C,QAAQ,SAASiD,GAC1BP,EAAEQ,eAAeD,KACnBJ,EAAWC,UAAUG,IACnBtC,KAAM,QACNsC,SAAUA,EACVI,OAAQV,EAAEM,IAEZK,EAAQG,WAI+B,IAAnCV,OAAOC,KAAKH,GAAYzH,QAAgB2H,OAAOC,KAAKH,EAAWC,WAAW1H,OAAS,EAAKyH,EAAa,KApD/G,GAAIS,IACFG,MAAO,EACPD,QAAS,EACTD,SAAU,GAoDRG,EAAQd,EAAsBF,EAAGC,EAKrC,OAJGe,KACDA,EAAMZ,UAAUQ,QAAUA,GAGrBI,GAIT7K,EAAS8K,kBAAoB,SAAUC,EAAKC,GAE1C,IAAK,GADDC,MACK5I,EAAI,EAAG6I,EAAOH,EAAIxI,OAAQ2I,EAAO,GAAKF,EAAI3I,EAAGA,GAAK,EAAG,CAC5D,GAAI8I,KACDxF,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,KAC5BsD,GAAIoF,EAAI1I,GAAIwD,GAAIkF,EAAI1I,EAAI,KACxBsD,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,KAC5BsD,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,IAE3B2I,GACG3I,EAEM6I,EAAO,IAAM7I,EACtB8I,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,IACnBG,EAAO,IAAM7I,IACtB8I,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,IAC5BI,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,KAL5BI,EAAE,IAAMxF,GAAIoF,EAAIG,EAAO,GAAIrF,GAAIkF,EAAIG,EAAO,IAQxCA,EAAO,IAAM7I,EACf8I,EAAE,GAAKA,EAAE,GACC9I,IACV8I,EAAE,IAAMxF,GAAIoF,EAAI1I,GAAIwD,GAAIkF,EAAI1I,EAAI,KAGpC4I,EAAE9F,QAEIgG,EAAE,GAAGxF,EAAI,EAAIwF,EAAE,GAAGxF,EAAIwF,EAAE,GAAGxF,GAAK,IAChCwF,EAAE,GAAGtF,EAAI,EAAIsF,EAAE,GAAGtF,EAAIsF,EAAE,GAAGtF,GAAK,GACjCsF,EAAE,GAAGxF,EAAI,EAAIwF,EAAE,GAAGxF,EAAIwF,EAAE,GAAGxF,GAAK,GAChCwF,EAAE,GAAGtF,EAAI,EAAIsF,EAAE,GAAGtF,EAAIsF,EAAE,GAAGtF,GAAK,EACjCsF,EAAE,GAAGxF,EACLwF,EAAE,GAAGtF,IAKX,MAAOoF,KAGT/K,OAAQC,SAAUH,GAOnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAASoL,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAOnG,KAAKoG,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAO/I,cACViJ,GAASF,UAIXE,GAASF,IAYtB,QAASzD,GAAKyD,EAAOnJ,GAEhBqJ,EAASF,IACVE,EAASF,GAAOnE,QAAQ,SAASoE,GAC/BA,EAAQpJ,KAKTqJ,EAAS,MACVA,EAAS,KAAKrE,QAAQ,SAASyE,GAC7BA,EAAYN,EAAOnJ,KAvDzB,GAAIqJ,KA4DJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpB5D,KAAMA,KAIV3H,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAAS6L,GAAYC,GACnB,GAAIC,KACJ,IAAID,EAAKvJ,OACP,IAAK,GAAIF,GAAI,EAAGA,EAAIyJ,EAAKvJ,OAAQF,IAC/B0J,EAAI5G,KAAK2G,EAAKzJ,GAGlB,OAAO0J,GA4CT,QAAStL,GAAOuL,EAAYC,GAC1B,GAAIC,GAAaD,GAAsBlM,KAAKoM,WAAanM,EAASoM,MAC9DC,EAAQnC,OAAOoC,OAAOJ,EAE1BlM,GAASoM,MAAMG,iBAAiBF,EAAOL,EAEvC,IAAIQ,GAAS,WACX,GACEC,GADEC,EAAKL,EAAMM,aAAe,YAU9B,OALAF,GAAW1M,OAASC,EAAWkK,OAAOoC,OAAOD,GAAStM,KACtD2M,EAAGE,MAAMH,EAAUI,MAAMV,UAAUW,MAAMC,KAAKC,UAAW,IAIlDP,EAOT,OAJAD,GAAOL,UAAYE,EACnBG,EAAOS,MAAQf,EACfM,EAAO/L,OAASV,KAAKU,OAEd+L,EA0FT,QAASU,GAAIC,EAAanB,GACxB,GAAGjM,OAASC,EAASoM,MACnB,KAAM,IAAIgB,OAAM,iFAIlB,IAAIC,QACDC,OAAOH,GACPI,IAAI,SAAUpB,GACb,MAAOA,aAAqBqB,UAAWrB,EAAUA,UAAYA,IAG7DsB,EAAkBzN,EAASoM,MAAMG,iBAAiBK,MAAMpK,OAAW6K,EAGvE,cADOI,GAAgBd,YAChB5M,KAAKU,OAAOuL,EAAYyB,GAIjC,QAASlB,KACP,GAAImB,GAAO7B,EAAYmB,WACnBtM,EAASgN,EAAK,EAYlB,OAVAA,GAAKhC,OAAO,EAAGgC,EAAKnL,OAAS,GAAG4E,QAAQ,SAAUxG,GAChDuJ,OAAOyD,oBAAoBhN,GAAQwG,QAAQ,SAAUyG,SAE5ClN,GAAOkN,GAEd1D,OAAO2D,eAAenN,EAAQkN,EAC5B1D,OAAO4D,yBAAyBnN,EAAQiN,QAIvClN,EAGTV,EAASoM,OACP3L,OAAQA,EACRyM,IAAKA,EACLX,iBAAkBA,IAGpBrM,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAaA,SAAS+N,KAEP,MADAhO,MAAKiO,YAAYjO,KAAK+I,gBAAgBK,gBAC/BpJ,KAQT,QAASkO,KAGP,MAFA/N,GAAOgO,oBAAoB,SAAUnO,KAAKoO,gBAC1CpO,KAAK+I,gBAAgBU,4BACdzJ,KAUT,QAASqO,GAAG9C,EAAOC,GAEjB,MADAxL,MAAKmH,aAAamE,gBAAgBC,EAAOC,GAClCxL,KAUT,QAASsO,GAAI/C,EAAOC,GAElB,MADAxL,MAAKmH,aAAauE,mBAAmBH,EAAOC,GACrCxL,KAYT,QAASuO,GAAKnN,EAAOgB,EAAMiB,EAAS4F,GAClCjJ,KAAKuB,UAAYtB,EAASkB,cAAcC,GACxCpB,KAAKoC,KAAOA,EACZpC,KAAKqD,QAAUA,EACfrD,KAAKiJ,kBAAoBA,EACzBjJ,KAAKmH,aAAelH,EAASoL,eAC7BrL,KAAK2G,sBAAwB1G,EAAS4B,IAAI2M,YAAY,iBACtDxO,KAAKyO,mBAAqBxO,EAAS4B,IAAI2M,YAAY,4BACnDxO,KAAKoO,eAAiB,WACpBpO,KAAKgO,UACLU,KAAK1O,MAEJA,KAAKuB,YAEHvB,KAAKuB,UAAUoN,cAChB3O,KAAKuB,UAAUoN,aAAaT,SAG9BlO,KAAKuB,UAAUoN,aAAe3O,MAGhCG,EAAOyO,iBAAiB,SAAU5O,KAAKoO,gBAIvCS,WAAW,WAIT7O,KAAK+I,gBAAkB9I,EAAS8I,mBAAoB/I,KAAKqD,QAASrD,KAAKiJ,kBAAmBjJ,KAAKmH,cAC/FnH,KAAKiO,YAAYjO,KAAK+I,gBAAgBK,iBACtCsF,KAAK1O,MAAO,GAIhBC,EAASsO,KAAOtO,EAASoM,MAAM3L,QAC7BkM,YAAa2B,EACbxF,gBAAiBtG,OACjBlB,UAAWkB,OACXd,IAAKc,OACL0E,aAAc1E,OACdwL,YAAa,WACX,KAAM,IAAIZ,OAAM,2CAElBW,OAAQA,EACRE,OAAQA,EACRG,GAAIA,EACJC,IAAKA,EACLpO,QAASD,EAASC,QAClByG,uBAAuB,KAGzBxG,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAuBA,SAAS4B,GAAIiN,EAAMpI,EAAYhF,EAAW8E,EAAQuI,GAE7CD,YAAgBE,YACjBhP,KAAKkC,MAAQ4M,GAEb9O,KAAKkC,MAAQ9B,EAAS6O,gBAAgBC,EAAOJ,GAGjC,QAATA,GACD9O,KAAKkC,MAAMiN,eAAeC,EAAOnP,EAASmP,MAAMC,cAAepP,EAASmP,MAAME,KAG7E5I,GACD1G,KAAK8B,KAAK4E,GAGThF,GACD1B,KAAK+B,SAASL,GAGb8E,IACGuI,GAAevI,EAAOtE,MAAMqN,WAC9B/I,EAAOtE,MAAMsN,aAAaxP,KAAKkC,MAAOsE,EAAOtE,MAAMqN,YAEnD/I,EAAOtE,MAAMD,YAAYjC,KAAKkC,SActC,QAASJ,GAAK4E,EAAY+I,GACxB,MAAyB,gBAAf/I,GACL+I,EACMzP,KAAKkC,MAAMwN,eAAeD,EAAI/I,GAE9B1G,KAAKkC,MAAMyN,aAAajJ,IAInCyD,OAAOC,KAAK1D,GAAYU,QAAQ,SAASwI,GAEhBnN,SAApBiE,EAAWkJ,KAIXH,EACDzP,KAAKkC,MAAMiN,eAAeM,GAAKxP,EAASmP,MAAMS,OAAQ,IAAKD,GAAK/H,KAAK,IAAKnB,EAAWkJ,IAErF5P,KAAKkC,MAAM4N,aAAaF,EAAKlJ,EAAWkJ,MAE1ClB,KAAK1O,OAEAA,MAaT,QAAS8G,GAAKgI,EAAMpI,EAAYhF,EAAWqN,GACzC,MAAO,IAAI9O,GAAS4B,IAAIiN,EAAMpI,EAAYhF,EAAW1B,KAAM+O,GAQ7D,QAASvI,KACP,MAAOxG,MAAKkC,MAAM6N,qBAAsBf,YAAa,GAAI/O,GAAS4B,IAAI7B,KAAKkC,MAAM6N,YAAc,KAQjG,QAAStQ,KAEP,IADA,GAAIuQ,GAAOhQ,KAAKkC,MACQ,QAAlB8N,EAAKC,UACTD,EAAOA,EAAKD,UAEd,OAAO,IAAI9P,GAAS4B,IAAImO,GAS1B,QAAS7O,GAAc+O,GACrB,GAAIC,GAAYnQ,KAAKkC,MAAMf,cAAc+O,EACzC,OAAOC,GAAY,GAAIlQ,GAAS4B,IAAIsO,GAAa,KASnD,QAASC,GAAiBF,GACxB,GAAIG,GAAarQ,KAAKkC,MAAMkO,iBAAiBF,EAC7C,OAAOG,GAAW7N,OAAS,GAAIvC,GAAS4B,IAAIyO,KAAKD,GAAc,KAajE,QAASxJ,GAAcD,EAASF,EAAYhF,EAAWqN,GAGrD,GAAsB,gBAAZnI,GAAsB,CAC9B,GAAIrF,GAAYnB,EAASmQ,cAAc,MACvChP,GAAUiP,UAAY5J,EACtBA,EAAUrF,EAAUgO,WAItB3I,EAAQkJ,aAAa,QAASW,EAI9B,IAAIC,GAAQ1Q,KAAK8G,KAAK,gBAAiBJ,EAAYhF,EAAWqN,EAK9D,OAFA2B,GAAMxO,MAAMD,YAAY2E,GAEjB8J,EAUT,QAASjK,GAAKkK,GAEZ,MADA3Q,MAAKkC,MAAMD,YAAY7B,EAASwQ,eAAeD,IACxC3Q,KAST,QAAS6Q,KACP,KAAO7Q,KAAKkC,MAAMqN,YAChBvP,KAAKkC,MAAMN,YAAY5B,KAAKkC,MAAMqN,WAGpC,OAAOvP,MAST,QAAS8Q,KAEP,MADA9Q,MAAKkC,MAAM6N,WAAWnO,YAAY5B,KAAKkC,OAChC,GAAIjC,GAAS4B,IAAI7B,KAAKkC,MAAM6N,YAUrC,QAAS/O,GAAQ+P,GAEf,MADA/Q,MAAKkC,MAAM6N,WAAWiB,aAAaD,EAAW7O,MAAOlC,KAAKkC,OACnD6O,EAWT,QAASE,GAAO/I,EAAS6G,GAOvB,MANGA,IAAe/O,KAAKkC,MAAMqN,WAC3BvP,KAAKkC,MAAMsN,aAAatH,EAAQhG,MAAOlC,KAAKkC,MAAMqN,YAElDvP,KAAKkC,MAAMD,YAAYiG,EAAQhG,OAG1BlC,KAST,QAASkR,KACP,MAAOlR,MAAKkC,MAAMyN,aAAa,SAAW3P,KAAKkC,MAAMyN,aAAa,SAASwB,OAAOC,MAAM,UAU1F,QAASrP,GAASsP,GAShB,MARArR,MAAKkC,MAAM4N,aAAa,QACtB9P,KAAKkR,QAAQlR,KAAKkC,OACfqL,OAAO8D,EAAMF,OAAOC,MAAM,QAC1BE,OAAO,SAASxK,EAAMU,EAAK+J,GAC1B,MAAOA,GAAK3F,QAAQ9E,KAAUU,IAC7BK,KAAK,MAGL7H,KAUT,QAASwR,GAAYH,GACnB,GAAII,GAAiBJ,EAAMF,OAAOC,MAAM,MAMxC,OAJApR,MAAKkC,MAAM4N,aAAa,QAAS9P,KAAKkR,QAAQlR,KAAKkC,OAAOoP,OAAO,SAASxC,GACxE,MAAwC,KAAjC2C,EAAe7F,QAAQkD,KAC7BjH,KAAK,MAED7H,KAST,QAAS0R,KAGP,MAFA1R,MAAKkC,MAAM4N,aAAa,QAAS,IAE1B9P,KAUT,QAASyB,KACP,MAAOzB,MAAKkC,MAAMyP,cAAgB7O,KAAKiC,MAAM/E,KAAKkC,MAAM0P,UAAUnQ,SAAWzB,KAAKkC,MAAM6N,WAAW4B,aAUrG,QAASnQ,KACP,MAAOxB,MAAKkC,MAAM2P,aAAe/O,KAAKiC,MAAM/E,KAAKkC,MAAM0P,UAAUpQ,QAAUxB,KAAKkC,MAAM6N,WAAW8B,YA4CnG,QAASC,GAAQC,EAAYC,EAAQ7K,GAiGnC,MAhGc1E,UAAXuP,IACDA,GAAS,GAGX7H,OAAOC,KAAK2H,GAAY3K,QAAQ,SAAoC6K,GAElE,QAASC,GAAcC,EAAqBH,GAC1C,GACEF,GACAM,EACAC,EAHEC,IAODH,GAAoBE,SAErBA,EAASF,EAAoBE,iBAAkBvF,OAC7CqF,EAAoBE,OACpBpS,EAAS4B,IAAI0Q,OAAOJ,EAAoBE,cACnCF,GAAoBE,QAI7BF,EAAoBK,MAAQvS,EAASgB,WAAWkR,EAAoBK,MAAO,MAC3EL,EAAoBM,IAAMxS,EAASgB,WAAWkR,EAAoBM,IAAK,MAEpEJ,IACDF,EAAoBO,SAAW,SAC/BP,EAAoBQ,WAAaN,EAAOxK,KAAK,KAC7CsK,EAAoBS,SAAW,OAI9BZ,IACDG,EAAoBU,KAAO,SAE3BP,EAAoBL,GAAaE,EAAoBW,KACrD9S,KAAK8B,KAAKwQ,GAIVF,EAAUnS,EAASa,UAAUqR,EAAoBK,OAAS,GAC1DL,EAAoBK,MAAQ,cAG9BV,EAAU9R,KAAK8G,KAAK,UAAW7G,EAASS,QACtCqS,cAAed,GACdE,IAEAH,GAEDnD,WAAW,WACTiD,EAAQ5P,MAAM8Q,gBACbZ,GAGFjL,GACD2K,EAAQ5P,MAAM0M,iBAAiB,aAAc,WAC3CzH,EAAaW,KAAK,kBAChBI,QAASlI,KACT8R,QAASA,EAAQ5P,MACjB+Q,OAAQd,KAEVzD,KAAK1O,OAGT8R,EAAQ5P,MAAM0M,iBAAiB,WAAY,WACtCzH,GACDA,EAAaW,KAAK,gBAChBI,QAASlI,KACT8R,QAASA,EAAQ5P,MACjB+Q,OAAQd,IAITH,IAEDM,EAAoBL,GAAaE,EAAoBe,GACrDlT,KAAK8B,KAAKwQ,GAEVR,EAAQhB,WAEVpC,KAAK1O,OAIN+R,EAAWE,YAAsBnF,OAClCiF,EAAWE,GAAW7K,QAAQ,SAAS+K,GACrCD,EAAcxD,KAAK1O,MAAMmS,GAAqB,IAC9CzD,KAAK1O,OAEPkS,EAAcxD,KAAK1O,MAAM+R,EAAWE,GAAYD,IAGlDtD,KAAK1O,OAEAA,KA+ET,QAASmT,GAAQC,GACf,GAAIrH,GAAO/L,IAEXA,MAAKqT,cACL,KAAI,GAAI/Q,GAAI,EAAGA,EAAI8Q,EAAS5Q,OAAQF,IAClCtC,KAAKqT,YAAYjO,KAAK,GAAInF,GAAS4B,IAAIuR,EAAS9Q,IAIlD6H,QAAOC,KAAKnK,EAAS4B,IAAIuK,WAAWkF,OAAO,SAASgC,GAClD,MAQ4C,MARpC,cACJ,SACA,gBACA,mBACA,UACA,SACA,UACA,SACA,SAAS1H,QAAQ0H,KACpBlM,QAAQ,SAASkM,GAClBvH,EAAKuH,GAAqB,WACxB,GAAI3F,GAAOb,MAAMV,UAAUW,MAAMC,KAAKC,UAAW,EAIjD,OAHAlB,GAAKsH,YAAYjM,QAAQ,SAASc,GAChCjI,EAAS4B,IAAIuK,UAAUkH,GAAmBzG,MAAM3E,EAASyF,KAEpD5B,KAnjBb,GAAImD,GAAQ,6BACVE,EAAQ,gCACRqB,EAAU,8BAEZxQ,GAASmP,OACPC,cAAe,WACfQ,OAAQ,KACRP,IAAK,6CAucPrP,EAAS4B,IAAM5B,EAASoM,MAAM3L,QAC5BkM,YAAa/K,EACbC,KAAMA,EACNgF,KAAMA,EACNN,OAAQA,EACR/G,KAAMA,EACN0B,cAAeA,EACfiP,iBAAkBA,EAClBvJ,cAAeA,EACfJ,KAAMA,EACNoK,MAAOA,EACPC,OAAQA,EACR9P,QAASA,EACTiQ,OAAQA,EACRC,QAASA,EACTnP,SAAUA,EACVyP,YAAaA,EACbE,iBAAkBA,EAClBjQ,OAAQA,EACRD,MAAOA,EACPsQ,QAASA,IAUX7R,EAAS4B,IAAI2M,YAAc,SAAS+E,GAClC,MAAOnT,GAASoT,eAAeC,WAAW,sCAAwCF,EAAS,OAQ7F,IAAIG,IACFC,YAAa,IAAM,EAAG,KAAO,MAC7BC,aAAc,IAAM,KAAO,KAAO,GAClCC,eAAgB,KAAO,IAAM,IAAM,KACnCC,YAAa,IAAM,KAAO,IAAM,KAChCC,aAAc,IAAM,IAAM,IAAM,KAChCC,eAAgB,KAAO,IAAM,KAAO,MACpCC,aAAc,IAAM,KAAO,KAAO,KAClCC,cAAe,KAAO,IAAM,KAAO,GACnCC,gBAAiB,KAAO,KAAO,KAAO,GACtCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,KAAO,IAAM,IAAM,GAClCC,gBAAiB,IAAM,EAAG,KAAO,GACjCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,IAAM,EAAG,IAAM,GAC9BC,gBAAiB,IAAM,EAAG,IAAM,GAChCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,IAAM,EAAG,IAAM,GAC7BC,eAAgB,EAAG,EAAG,EAAG,GACzBC,YAAa,GAAK,IAAM,IAAM,MAC9BC,aAAc,KAAO,IAAM,KAAO,GAClCC,eAAgB,KAAO,KAAO,IAAM,KACpCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,KAAO,KAAO,IAAM,OAClCC,eAAgB,KAAO,IAAM,KAAO,MAGtCjV,GAAS4B,IAAI0Q,OAASmB,EAwCtBzT,EAAS4B,IAAIyO,KAAOrQ,EAASoM,MAAM3L,QACjCkM,YAAauG,KAGfhT,OAAQC,SAAUH,GASnB,SAASE,EAAQC,EAAUH,GAC1B,YAiDA,SAASgO,GAAY5K,GACnB,GACED,GADE+R,KAEF/Q,EAAiBnE,EAAS0C,mBAAmB1C,EAASkC,aAAanC,KAAKoC,MAAOpC,KAAKoC,KAAK8E,OAAO1E,OAGlGxC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAGhGhS,EAASnD,EAASkE,UAAUnE,KAAK2B,IAAKyC,EAAgBf,EAEtD,IAAI2D,GAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,GAE/C6D,EAASlH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW0N,YAC1DpO,EAAOjH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW2N,UAExDrV,GAAS8G,YAAYC,EAAWhH,KAAKoC,KAAM6E,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,uBAC1F1G,EAAS2I,YAAY5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAChD6S,EAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,KAG7B9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAMP,KAAK,GAJDuD,GAEFoK,EADAC,KAGO/S,EAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAC5C0I,EAAInL,EAAS6I,aAAa9B,EAAW5D,EAAQgB,EAAe9B,GAAII,GAChE+S,EAAgBrQ,KAAKgG,EAAExF,EAAGwF,EAAEtF,GAIxBzC,EAAQqS,YACVF,EAAQL,EAAa7S,GAAGwE,KAAK,QAC3BX,GAAIiF,EAAExF,EACNQ,GAAIgF,EAAEtF,EACNO,GAAI+E,EAAExF,EAAI,IACVU,GAAI8E,EAAEtF,GACLzC,EAAQsE,WAAW6N,OAAO1T,MAC3Bf,MAASqD,EAAe9B,GAAGI,IAC1BzC,EAASmP,MAAME,KAElBtP,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNhH,MAAOqD,EAAe9B,GAAGI,GACzB2E,MAAO3E,EACPuF,MAAOkN,EAAa7S,GACpB4F,QAASsN,EACT5P,EAAGwF,EAAExF,EACLE,EAAGsF,EAAEtF,IAMX,IAAIzC,EAAQsS,UAAYtS,EAAQuS,SAAU,CAExC,GAAIC,IAAgB,IAAMJ,EAAgB,GAAK,IAAMA,EAAgB,GAGrE,IAAIpS,EAAQyS,YAAcL,EAAgBjT,OAAS,EAGjD,IAAI,GADAuT,GAAK9V,EAAS8K,kBAAkB0K,GAC5BO,EAAI,EAAGA,EAAID,EAAGvT,OAAQwT,IAC5BH,EAAazQ,KAAK,IAAM2Q,EAAGC,GAAGnO,YAGhC,KAAI,GAAIoO,GAAI,EAAGA,EAAIR,EAAgBjT,OAAQyT,GAAK,EAC9CJ,EAAazQ,KAAK,IAAMqQ,EAAgBQ,EAAI,GAAK,IAAMR,EAAgBQ,GAI3E,IAAG5S,EAAQuS,SAAU,CAGnB,GAAIM,GAAWpT,KAAKW,IAAIX,KAAK0B,IAAInB,EAAQ6S,SAAU9S,EAAOK,KAAML,EAAOoB,KAGnE2R,EAAmBN,EAAa9I,QAGhCqJ,EAAoBnW,EAAS6I,aAAa9B,EAAW5D,GAAS8S,GAAW,EAE7EC,GAAiBxK,OAAO,EAAG,EAAG,IAAMyK,EAAkBxQ,EAAI,IAAMwQ,EAAkBtQ,GAClFqQ,EAAiB,GAAK,IAAMV,EAAgB,GAAK,IAAMA,EAAgB,GACvEU,EAAiB/Q,KAAK,IAAMqQ,EAAgBA,EAAgBjT,OAAS,GAAK,IAAM4T,EAAkBtQ,EAGlG,IAAIuQ,GAAOlB,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAGiL,EAAiBtO,KAAK,KACxBxE,EAAQsE,WAAW0O,MAAM,GAAMvU,MAChCqD,OAAUf,EAAe9B,IACxBrC,EAASmP,MAAME,IAElBtP,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,OACN5C,OAAQf,EAAe9B,GACvB+E,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASmO,IAIb,GAAGhT,EAAQsS,SAAU,CACnB,GAAIW,GAAOnB,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAG2K,EAAahO,KAAK,KACpBxE,EAAQsE,WAAW2O,MAAM,GAAMxU,MAChCqD,OAAUf,EAAe9B,IACxBrC,EAASmP,MAAME,IAElBtP,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,OACN5C,OAAQf,EAAe9B,GACvB+E,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASoO,MAMjBtW,KAAKmH,aAAaW,KAAK,WACrB1E,OAAQA,EACR4D,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAgJb,QAASkT,GAAKnV,EAAOgB,EAAMiB,EAAS4F,GAClChJ,EAASsW,KAAKrJ,MAAMN,YAAYI,KAAKhN,KACnCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GAhVJ,GAAID,IACFrF,OACEC,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,MAElC4E,OACErB,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,KAChC6E,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRkT,UAAU,EACVD,WAAW,EACXE,UAAU,EACVM,SAAU,EACVJ,YAAY,EACZ5R,IAAKzB,OACLsB,KAAMtB,OACNiB,aAAc,EACdiE,YACEyN,MAAO,gBACP7M,MAAO,WACP8M,WAAY,YACZ9S,OAAQ,YACR+T,KAAM,UACNd,MAAO,WACPa,KAAM,UACNpP,KAAM,UACNqO,UAAW,WACXzM,SAAU,cACVjB,WAAY,iBAyShB3H,GAASsW,KAAOtW,EAASsO,KAAK7N,QAC5BkM,YAAa2J,EACbtI,YAAaA,KAGf9N,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA2CA,SAASgO,GAAY5K,GACnB,GACED,GADE+R,KAEF/Q,EAAiBnE,EAAS0C,mBAAmB1C,EAASkC,aAAanC,KAAKoC,MAAOpC,KAAKoC,KAAK8E,OAAO1E,OAGlGxC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAGhGhS,EAASnD,EAASkE,UAAUnE,KAAK2B,IAAKyC,EAAgBf,EAAS,EAE/D,IAAI2D,GAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,GAE/C6D,EAASlH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW0N,YAC1DpO,EAAOjH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW2N,WAEtDkB,EAAYvW,EAAS6I,aAAa9B,EAAW5D,GAAS,GAAI,EAE5DnD,GAAS8G,YAAYC,EAAWhH,KAAKoC,KAAM6E,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,uBAC1F1G,EAAS2I,YAAY5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAEhD,GAAImU,GAAQnU,GAAKtC,KAAKoC,KAAKG,OAAOC,OAAS,GAAK,EAE9CkU,EAAkB1P,EAAUxF,QAAU4C,EAAe9B,GAAGE,OAAS,CAEnE2S,GAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,KAG7B9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAEP,KAAI,GAAInF,GAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAAK,CAChD,GACEiU,GADEvL,EAAInL,EAAS6I,aAAa9B,EAAW5D,EAAQgB,EAAe9B,GAAII,EAKpE0I,GAAExF,GAAK8Q,EAAmBD,EAAQpT,EAAQuT,kBAE1CD,EAAMxB,EAAa7S,GAAGwE,KAAK,QACzBX,GAAIiF,EAAExF,EACNQ,GAAIoQ,EAAU1Q,EACdO,GAAI+E,EAAExF,EACNU,GAAI8E,EAAEtF,GACLzC,EAAQsE,WAAWgP,KAAK7U,MACzBf,MAASqD,EAAe9B,GAAGI,IAC1BzC,EAASmP,MAAME,KAElBtP,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,MACNhH,MAAOqD,EAAe9B,GAAGI,GACzB2E,MAAO3E,EACPuF,MAAOkN,EAAa7S,GACpB4F,QAASyO,EACTxQ,GAAIiF,EAAExF,EACNQ,GAAIoQ,EAAU1Q,EACdO,GAAI+E,EAAExF,EACNU,GAAI8E,EAAEtF,KAKZ9F,KAAKmH,aAAaW,KAAK,WACrB1E,OAAQA,EACR4D,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAwGb,QAASwT,GAAIzV,EAAOgB,EAAMiB,EAAS4F,GACjChJ,EAAS4W,IAAI3J,MAAMN,YAAYI,KAAKhN,KAClCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GArOJ,GAAID,IACFrF,OACEC,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,MAElC4E,OACErB,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,KAChC6E,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRsB,KAAMtB,OACNyB,IAAKzB,OACLiB,aAAc,EACdkT,kBAAmB,GACnBjP,YACEyN,MAAO,eACP7M,MAAO,WACP8M,WAAY,YACZ9S,OAAQ,YACRoU,IAAK,SACL1P,KAAM,UACNqO,UAAW,WACXzM,SAAU,cACVjB,WAAY,iBAoMhB3H,GAAS4W,IAAM5W,EAASsO,KAAK7N,QAC3BkM,YAAaiK,EACb5I,YAAaA,KAGf9N,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAwBA,SAAS6W,GAAwBC,EAAQxO,EAAOyO,GAC9C,GAAIC,GAAa1O,EAAM3C,EAAImR,EAAOnR,CAElC,OAAGqR,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SAIX,QAAS/I,GAAY5K,GACnB,GACE2D,GACAxB,EACA0R,EACAC,EAJEhC,KAKFiC,EAAa/T,EAAQ+T,WACrBxU,EAAY3C,EAASkC,aAAanC,KAAKoC,KAGzCpC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAEhGpO,EAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,EAAS,EAAG,GAE3DmC,EAAS1C,KAAK0B,IAAIwC,EAAUxF,QAAU,EAAGwF,EAAUvF,SAAW,GAE9D0V,EAAe9T,EAAQgU,OAASzU,EAAU0U,OAAO,SAASC,EAAeC,GACvE,MAAOD,GAAgBC,GACtB,GAKHhS,GAAUnC,EAAQoU,MAAQpU,EAAQqU,WAAa,EAAK,EAIpDR,EAAc7T,EAAQoU,MAAQjS,EAASA,EAAS,EAEhD0R,GAAe7T,EAAQgF,WAevB,KAAK,GAZD0O,IACFnR,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAU,EACtCsE,EAAGkB,EAAUV,GAAKU,EAAUvF,SAAW,GAIrCkW,EAEU,IAFa3X,KAAKoC,KAAKG,OAAO+O,OAAO,SAASsG,GAC1D,MAAe,KAARA,IACNpV,OAIMF,EAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAChD6S,EAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,IAAK,KAAM,MAAM,GAG9C9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAEP,IAAIgQ,GAAWT,EAAaxU,EAAUN,GAAK6U,EAAe,GAGvDU,GAAWT,IAAe,MAC3BS,GAAY,IAGd,IAAIC,GAAQ7X,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGN,EAAQ4R,GAAoB,IAAN9U,GAAWqV,EAAuB,EAAI,KACpHI,EAAM9X,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGN,EAAQqS,GAC5DG,EAAoC,KAAzBH,EAAWT,EAAoB,IAAM,IAChDlM,GAEE,IAAK6M,EAAInS,EAAGmS,EAAIjS,EAEhB,IAAKN,EAAQA,EAAQ,EAAGwS,EAAU,EAAGF,EAAMlS,EAAGkS,EAAMhS,EAIrDzC,GAAQoU,SAAU,GACnBvM,EAAE9F,KAAK,IAAK2R,EAAOnR,EAAGmR,EAAOjR,EAK/B,IAAImS,GAAO9C,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAGA,EAAErD,KAAK,MACTxE,EAAQsE,WAAWoF,OAAS1J,EAAQoU,MAAQ,IAAMpU,EAAQsE,WAAW8P,MAAQ,IA6BhF,IA1BAQ,EAAKnW,MACHf,MAAS6B,EAAUN,IAClBrC,EAASmP,MAAME,KAGfjM,EAAQoU,SAAU,GACnBQ,EAAKnW,MACHE,MAAS,mBAAqBqB,EAAQqU,WAAc,OAKxD1X,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNhH,MAAO6B,EAAUN,GACjB6U,aAAcA,EACd9P,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAAS+P,EACTlB,OAAQA,EACRvR,OAAQA,EACR4R,WAAYA,EACZS,SAAUA,IAITxU,EAAQ8E,UAAW,CAEpB,GAAIC,GAAgBnI,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGoR,EAAaE,GAAcS,EAAWT,GAAc,GACpH9P,EAAoBjE,EAAQkE,sBAAsBvH,KAAKoC,KAAK8E,OAASlH,KAAKoC,KAAK8E,OAAO5E,GAAKM,EAAUN,GAAIA,GAEvGgG,EAAe6M,EAAa7S,GAAGwE,KAAK,QACtCoR,GAAI9P,EAAcxC,EAClBuS,GAAI/P,EAActC,EAClBsS,cAAetB,EAAwBC,EAAQ3O,EAAe/E,EAAQgV,iBACrEhV,EAAQsE,WAAWY,OAAO9B,KAAK,GAAKa,EAGvCtH,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNV,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,IAMrBsR,EAAaS,EAGf7X,KAAKmH,aAAaW,KAAK,WACrBd,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAoFb,QAASiV,GAAIlX,EAAOgB,EAAMiB,EAAS4F,GACjChJ,EAASqY,IAAIpL,MAAMN,YAAYI,KAAKhN,KAClCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GA/QJ,GAAID,IACFxH,MAAOiB,OACPhB,OAAQgB,OACRiB,aAAc,EACdiE,YACEyN,MAAO,eACP7S,OAAQ,YACRwK,MAAO,WACP0K,MAAO,WACPlP,MAAO,YAET6O,WAAY,EACZC,MAAO5U,OACPgV,OAAO,EACPC,WAAY,GACZvP,WAAW,EACXE,YAAa,EACbd,sBAAuBtH,EAASI,KAChCkY,eAAe,EACfF,eAAgB,UAgQlBpY,GAASqY,IAAMrY,EAASsO,KAAK7N,QAC3BkM,YAAa0L,EACbrK,YAAaA,EACb6I,wBAAyBA,KAG3B3W,OAAQC,SAAUH,GAGbA","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas\n /**\n * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property\n * where deltas for specific object properties can be found for the given object nesting level. For nested objects the\n * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also\n * contain a __delta__ property with the deltas of their level.\n *\n * @param {Object|Array} a Object that should be used to analyzed delta to object b\n * @param {Object|Array} b The second object where the deltas from a should be analyzed\n * @returns {Object} Delta descriptor object or null\n */\n Chartist.deltaDescriptor = function(a, b) {\n var summary = {\n added: 0,\n removed: 0,\n modified: 0\n };\n\n function findDeltasRecursively(a, b) {\n var descriptor = {\n __delta__: {}\n };\n\n // First check for removed and modified properties\n Object.keys(a).forEach(function(property) {\n if(!b.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'remove',\n property: property,\n ours: a[property]\n };\n summary.removed++;\n } else {\n if(typeof a[property] === 'object') {\n var subDescriptor = findDeltasRecursively(a[property], b[property]);\n if(subDescriptor) {\n descriptor[property] = subDescriptor;\n }\n } else {\n if(a[property] !== b[property]) {\n descriptor.__delta__[property] = {\n type: 'modify',\n property: property,\n ours: a[property],\n theirs: b[property]\n };\n summary.modified++;\n }\n }\n }\n });\n\n // Check for added properties\n Object.keys(b).forEach(function(property) {\n if(!a.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'added',\n property: property,\n theirs: b[property]\n };\n summary.added++;\n }\n });\n\n return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null;\n }\n\n var delta = findDeltasRecursively(a, b);\n if(delta) {\n delta.__delta__.summary = summary;\n }\n\n return delta;\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n\n}));\n"]} \ No newline at end of file diff --git a/libdist/scss/_modules.scss b/dist/scss/_modules.scss similarity index 76% rename from libdist/scss/_modules.scss rename to dist/scss/_modules.scss index 41ecb6ca..938b5eac 100644 --- a/libdist/scss/_modules.scss +++ b/dist/scss/_modules.scss @@ -1,3 +1,5 @@ @import "http://github.com/modules/common"; @import "http://github.com/modules/scale"; @import "http://github.com/modules/animation"; + +// not reuqired, used ? diff --git a/libdist/scss/chartist.scss b/dist/scss/chartist.scss similarity index 99% rename from libdist/scss/chartist.scss rename to dist/scss/chartist.scss index a8cfc7c2..1b2f8c43 100644 --- a/libdist/scss/chartist.scss +++ b/dist/scss/chartist.scss @@ -149,4 +149,4 @@ } } } -} \ No newline at end of file +} diff --git a/libdist/scss/modules/_animation.scss b/dist/scss/modules/_animation.scss similarity index 100% rename from libdist/scss/modules/_animation.scss rename to dist/scss/modules/_animation.scss diff --git a/libdist/scss/modules/_common.scss b/dist/scss/modules/_common.scss similarity index 100% rename from libdist/scss/modules/_common.scss rename to dist/scss/modules/_common.scss diff --git a/libdist/scss/modules/_scale.scss b/dist/scss/modules/_scale.scss similarity index 100% rename from libdist/scss/modules/_scale.scss rename to dist/scss/modules/_scale.scss diff --git a/libdist/scss/settings/_chartist-settings.scss b/dist/scss/settings/_chartist-settings.scss similarity index 100% rename from libdist/scss/settings/_chartist-settings.scss rename to dist/scss/settings/_chartist-settings.scss diff --git a/libdist/chartist.min.js b/libdist/chartist.min.js deleted file mode 100644 index eae0aa26..00000000 --- a/libdist/chartist.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Chartist.js 0.4.1 - * Copyright © 2014 Gion Kunz - * Free to use under the WTFPL license. - * http://www.wtfpl.net/ - */ - -!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define([],b):a.Chartist=b()}(this,function(){var a={};return a.version="0.3.1",function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;j0?e:null}var d={added:0,removed:0,modified:0},e=c(a,b);return e&&(e.__delta__.summary=d),e},c.catmullRom2bezier=function(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); -//# sourceMappingURL=chartist.min.map \ No newline at end of file diff --git a/libdist/chartist.min.map b/libdist/chartist.min.map deleted file mode 100644 index 1c4095ee..00000000 --- a/libdist/chartist.min.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","exports","module","define","amd","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18761,"pos":18756,"col":16,"line":493,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18761,"pos":18756,"col":16,"line":493,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","deltaDescriptor","a","b","findDeltasRecursively","descriptor","__delta__","Object","keys","property","hasOwnProperty","subDescriptor","ours","theirs","summary","modified","removed","added","delta","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function(root, factory) {\n if(typeof exports === 'object') {\n module.exports = factory();\n }\n else if(typeof define === 'function' && define.amd) {\n define([], factory);\n }\n else {\n root['Chartist'] = factory();\n }\n}(this, function() {\n\n /* Chartist.js 0.4.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {};\n Chartist.version = '0.3.1';\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas\n /**\n * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property\n * where deltas for specific object properties can be found for the given object nesting level. For nested objects the\n * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also\n * contain a __delta__ property with the deltas of their level.\n *\n * @param {Object|Array} a Object that should be used to analyzed delta to object b\n * @param {Object|Array} b The second object where the deltas from a should be analyzed\n * @returns {Object} Delta descriptor object or null\n */\n Chartist.deltaDescriptor = function(a, b) {\n var summary = {\n added: 0,\n removed: 0,\n modified: 0\n };\n\n function findDeltasRecursively(a, b) {\n var descriptor = {\n __delta__: {}\n };\n\n // First check for removed and modified properties\n Object.keys(a).forEach(function(property) {\n if(!b.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'remove',\n property: property,\n ours: a[property]\n };\n summary.removed++;\n } else {\n if(typeof a[property] === 'object') {\n var subDescriptor = findDeltasRecursively(a[property], b[property]);\n if(subDescriptor) {\n descriptor[property] = subDescriptor;\n }\n } else {\n if(a[property] !== b[property]) {\n descriptor.__delta__[property] = {\n type: 'modify',\n property: property,\n ours: a[property],\n theirs: b[property]\n };\n summary.modified++;\n }\n }\n }\n });\n\n // Check for added properties\n Object.keys(b).forEach(function(property) {\n if(!a.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'added',\n property: property,\n theirs: b[property]\n };\n summary.added++;\n }\n });\n\n return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null;\n }\n\n var delta = findDeltasRecursively(a, b);\n if(delta) {\n delta.__delta__.summary = summary;\n }\n\n return delta;\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n}));\n"]} \ No newline at end of file From 53dc8bb939d5d47ef075671e94efbc0d63a5a2aa Mon Sep 17 00:00:00 2001 From: Autarc Date: Tue, 25 Nov 2014 09:52:53 +0100 Subject: [PATCH 095/593] update task structure --- CONTRIBUTING.md | 13 +++++++------ package.json | 14 +++++++++----- tasks/aliases.yml | 41 ++++++++++++++++++++++++----------------- tasks/assemble.js | 15 +++++++++------ tasks/clean.js | 11 ++++++----- tasks/concat.js | 31 +++++++++++++++++++++---------- tasks/concurrent.js | 8 ++++---- tasks/connect.js | 19 +++++++++++-------- tasks/copy.js | 22 +++++++++++----------- tasks/critical.js | 8 ++++---- tasks/cssmin.js | 4 ++-- tasks/doxication.js | 16 +++++++++------- tasks/htmlmin.js | 6 +++--- tasks/imagemin.js | 4 ++-- tasks/jasmine.js | 20 ++++++++++---------- tasks/jshint.js | 7 ++++--- tasks/sass.js | 30 ++++++++++++++++++++++-------- tasks/svgmin.js | 4 ++-- tasks/uglify.js | 14 +++++++++++--- tasks/umd.js | 4 ++-- tasks/usemin.js | 6 +++--- tasks/useminPrepare.js | 4 ++-- tasks/watch.js | 24 +++++++++++++++--------- 23 files changed, 193 insertions(+), 132 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 529c9ba1..11e3eeb1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,14 +37,15 @@ Check out the [Coding Style document](CODINGSTYLE.md) ### Grunt -We have three grunt tasks: +We have five grunt tasks: -1. `grunt build` - Creates the distribution of the example / demo site which is used as visual development help of the charts but also serves as the documentation site / gh-pages. -2. `grunt serve` - Starts watch with livereload that is executing the same things as the site dist default task but for live development. -3. `grunt test` - Executes jasmine tests separately, although we have a very big lack of tests. -4. `grunt serve:dist` - Executes a dist and serves the directory statically in order to serve with the production example / demo site. +1. `grunt build` - Combines the scripts and creates the library for distribution +2. `grunt public` - Creates the distribution of the example / demo site which is used as visual development help of the charts but also serves as the documentation site / gh-pages. +3. `grunt dev` - Starts watch with livereload that is executing the same things as the site build default task but for live development. +4. `grunt preview` - Executes a dist and serves the directory statically in order to serve with the production example / demo site. +5. `grunt test` - Executes jasmine tests separately, although we have a very big lack of tests. -`libdist` should **not** be included in any Pull Requests. So please ensure that code is not being committed as part of the Pull Request. +`dist` should **not** be included in any Pull Requests. So please ensure that code is not being committed as part of the Pull Request. ### Documentation diff --git a/package.json b/package.json index a39fbb6b..60602160 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "package.json", "README.md" ], - "main": "libdist/chartist.js", - "browser": "libdist/chartist.js", + "main": "dist/chartist.js", + "browser": "dist/chartist.js", "licenses": [ { "type": "WTFPL", @@ -54,7 +54,7 @@ "grunt-newer": "^0.8.0", "grunt-sass": "~0.14.2", "grunt-svgmin": "~0.2.0", - "grunt-umd": "^2.0.1", + "grunt-umd": "~2.0.0", "grunt-usemin": "~2.3.0", "handlebars-helpers": "~0.5.5", "jasmine-fixture": "~1.0.8", @@ -72,7 +72,11 @@ }, "config": { "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\n */\n", - "source": "source", - "dist": "sitedist" + "src": "src", + "dist": "dist", + "site": "site", + "tmp": ".tmp", + "public": ".public", + "test": "test" } } diff --git a/tasks/aliases.yml b/tasks/aliases.yml index 9064942c..06a85555 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -7,43 +7,50 @@ default: - 'newer:jshint' - 'test' - 'build' + - 'dev' -libdist: - - 'copy:libdist' - - 'concat:libdist' - - 'umd:libdist' - - 'uglify:libdist' - - 'sass:dist' - - 'cssmin:libdist' - +# create the library build: - 'clean:dist' + - 'copy:dist' + - 'concat:dist' + - 'umd' + - 'uglify:dist' + - 'sass:dist' + - 'cssmin' + +# prepare the website +public: + - 'clean:public' - 'doxication' - 'assemble' - 'useminPrepare' - - 'concurrent:dist' + - 'concurrent:public' - 'concat:generated' - - 'copy:dist' + - 'copy:public' - 'cssmin:generated' - 'uglify:generated' - 'usemin' - 'critical' - 'htmlmin' + - 'concat:public' + - 'uglify:public' +# tests test: - - 'clean:server' + - 'clean:tmp' - 'concurrent:test' - 'connect:test' - 'jasmine' -live: - - 'clean:server' - - 'doxication' - - 'assemble' - - 'concurrent:server' +# local version with livereload +dev: + - 'public' - 'connect:livereload' - 'watch' +# online version preview: - 'build' - - 'connect:dist:keepalive' + - 'public' + - 'connect:public' diff --git a/tasks/assemble.js b/tasks/assemble.js index c0293efa..2527caba 100644 --- a/tasks/assemble.js +++ b/tasks/assemble.js @@ -12,18 +12,21 @@ module.exports = function (grunt) { return { options: { - helpers: ['<%= pkg.config.source %>/site/helpers/**/*.js'], - partials: ['<%= pkg.config.source %>/site/partials/**/*.hbs'], - layoutdir: '<%= pkg.config.source %>/site/layouts', + helpers: ['<%= pkg.config.site %>/templates/helpers/**/*.js'], + partials: ['<%= pkg.config.site %>/templates/partials/**/*.hbs'], + layoutdir: '<%= pkg.config.site %>/templates/layouts', layoutext: '.hbs', layout: ['default'], - data: ['<%= pkg.config.source %>/site/data/**/*.{json,yml}', '.tmp/data/**/*.{json,yml}'] + data: [ + '<%= pkg.config.site %>/templates/data/**/*.{json,yml}', + '<%= pkg.config.tmp %>/data/**/*.{json,yml}' + ] }, pages: { expand: true, - cwd: '<%= pkg.config.source %>/site', + cwd: '<%= pkg.config.site %>/templates', src: ['*.hbs'], - dest: '.tmp' + dest: '<%= pkg.config.tmp %>' } }; }; diff --git a/tasks/clean.js b/tasks/clean.js index ac66020e..71dd9bae 100644 --- a/tasks/clean.js +++ b/tasks/clean.js @@ -11,18 +11,19 @@ module.exports = function (grunt) { return { - dist: { + public: { files: [ { dot: true, src: [ - '.tmp', - '<%= pkg.config.dist %>/*', - '!<%= pkg.config.dist %>/.git*' + '<%= pkg.config.tmp %>', + '<%= pkg.config.public %>/*', + '!<%= pkg.config.public %>/.git*' ] } ] }, - server: '.tmp' + tmp: '<%= pkg.config.tmp %>', + dist: '<%= pkg.config.dist %>' }; }; diff --git a/tasks/concat.js b/tasks/concat.js index 1f759a68..96306e85 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -11,21 +11,32 @@ module.exports = function (grunt) { return { - libdist: { + dist: { options: { separator: ';', banner: '<%= pkg.config.banner %>' }, files: { - 'libdist/chartist.js': [ - 'source/scripts/chartist.core.js', - 'source/scripts/chartist.event.js', - 'source/scripts/chartist.class.js', - 'source/scripts/chartist.base.js', - 'source/scripts/chartist.svg.js', - 'source/scripts/chartist.line.js', - 'source/scripts/chartist.bar.js', - 'source/scripts/chartist.pie.js' + '<%= pkg.config.dist %>/chartist.js': [ + '<%= pkg.config.src %>/core.js', + '<%= pkg.config.src %>/event.js', + '<%= pkg.config.src %>/class.js', + '<%= pkg.config.src %>/base.js', + '<%= pkg.config.src %>/svg.js', + '<%= pkg.config.src %>/types/line.js', + '<%= pkg.config.src %>/types/bar.js', + '<%= pkg.config.src %>/types/pie.js' + ] + } + }, + public: { + options: { + separator: ';', + }, + files: { + '<%= pkg.config.public %>/scripts/all.js': [ + '<%= pkg.config.dist %>/chartist.js', + '<%= pkg.config.public %>/scripts/all.js' ] } } diff --git a/tasks/concurrent.js b/tasks/concurrent.js index d4c4f3c6..28c5853c 100644 --- a/tasks/concurrent.js +++ b/tasks/concurrent.js @@ -12,13 +12,13 @@ module.exports = function (grunt) { return { server: [ - 'sass:server' + 'sass:public' ], test: [ - 'sass' + 'sass' // tmp ], - dist: [ - 'sass:dist', + public: [ + 'sass:public', 'imagemin', 'svgmin' ] diff --git a/tasks/connect.js b/tasks/connect.js index 9e537c85..1d8c608c 100644 --- a/tasks/connect.js +++ b/tasks/connect.js @@ -14,15 +14,16 @@ module.exports = function (grunt) { options: { port: 9000, // Change this to '0.0.0.0' to access the server from outside. - hostname: '0.0.0.0', + hostname: 'localhost', livereload: 35729 }, livereload: { options: { open: true, base: [ - '.tmp', - '<%= pkg.config.source %>' + '<%= pkg.config.tmp %>', + '<%= pkg.config.src %>', + '<%= pkg.config.site %>' ] } }, @@ -30,15 +31,17 @@ module.exports = function (grunt) { options: { port: 9001, base: [ - '.tmp', - 'test', - '<%= pkg.config.source %>' + '<%= pkg.config.tmp %>', + '<%= pkg.config.test %>', + '<%= pkg.config.site %>' ] } }, - dist: { + public: { options: { - base: '<%= pkg.config.dist %>' + open: true, + keepalive: true, + base: '<%= pkg.config.public %>' } } }; diff --git a/tasks/copy.js b/tasks/copy.js index 505cb726..3b99c9cc 100644 --- a/tasks/copy.js +++ b/tasks/copy.js @@ -11,13 +11,13 @@ module.exports = function (grunt) { return { - dist: { + public: { files: [ { expand: true, dot: true, - cwd: '<%= pkg.config.source %>', - dest: '<%= pkg.config.dist %>', + cwd: '<%= pkg.config.site %>', + dest: '<%= pkg.config.public %>', src: [ '*.{ico,png,txt}', '.htaccess', @@ -29,26 +29,26 @@ module.exports = function (grunt) { }, { expand: true, - cwd: '.tmp/images', - dest: '<%= pkg.config.dist %>/images', + cwd: '<%= pkg.config.tmp %>/images', + dest: '<%= pkg.config.public %>/images', src: ['generated/*'] }, { expand: true, - cwd: '.tmp', - dest: '<%= pkg.config.dist %>', + cwd: '<%= pkg.config.tmp %>', + dest: '<%= pkg.config.public %>', src: [ '*.html' ] } ] }, - libdist: { + dist: { files: [ { expand: true, - cwd: '<%= pkg.config.source %>/styles', - dest: 'libdist/scss/', + cwd: '<%= pkg.config.src %>/styles', + dest: '<%= pkg.config.dist %>/scss/', src: [ 'modules/**/*.scss', 'settings/**/*.scss', @@ -56,7 +56,7 @@ module.exports = function (grunt) { ] }, { - dest: 'libdist/', + dest: '<%= pkg.config.dist %>/', src: 'LICENSE' } ] diff --git a/tasks/critical.js b/tasks/critical.js index a9dec1c4..515b92ed 100644 --- a/tasks/critical.js +++ b/tasks/critical.js @@ -11,15 +11,15 @@ module.exports = function (grunt) { return { - dist: { + public: { options: { base: './', - css: '<%= pkg.config.dist %>/styles/main.css', + css: '<%= pkg.config.public %>/styles/main.css', width: 320, height: 3000 }, - src: '<%= pkg.config.dist %>/index.html', - dest: '<%= pkg.config.dist %>/index.html' + src: '<%= pkg.config.public %>/index.html', + dest: '<%= pkg.config.public %>/index.html' } }; }; diff --git a/tasks/cssmin.js b/tasks/cssmin.js index 2e81d160..0fa900d2 100644 --- a/tasks/cssmin.js +++ b/tasks/cssmin.js @@ -11,12 +11,12 @@ module.exports = function (grunt) { return { - libdist: { + dist: { options: { 'banner': '<%= pkg.config.banner %>' }, files: { - 'libdist/chartist.min.css': ['.tmp/styles/chartist.css'] + '<%= pkg.config.dist %>/chartist.min.css': ['<%= pkg.config.tmp %>/styles/chartist.css'] } } }; diff --git a/tasks/doxication.js b/tasks/doxication.js index 4fa232ae..126abedd 100644 --- a/tasks/doxication.js +++ b/tasks/doxication.js @@ -11,12 +11,14 @@ module.exports = function (grunt) { return { - all: { - options: { - format: 'yml' - }, - src: ['source/scripts/*.js'], - dest: '.tmp/data/apidox.yml' - } + all: { + options: { + format: 'yml' + }, + src: [ + '<%= pkg.config.src %>/{,*/}*.js' + ], + dest: '<%= pkg.config.tmp %>/data/apidox.yml' + } }; }; diff --git a/tasks/htmlmin.js b/tasks/htmlmin.js index 4e9d3547..effaffa5 100644 --- a/tasks/htmlmin.js +++ b/tasks/htmlmin.js @@ -11,7 +11,7 @@ module.exports = function(){ return { - dist: { + public: { options: { collapseWhitespace: true, collapseBooleanAttributes: true, @@ -21,9 +21,9 @@ module.exports = function(){ files: [ { expand: true, - cwd: '<%= pkg.config.dist %>', + cwd: '<%= pkg.config.public %>', src: ['*.html'], - dest: '<%= pkg.config.dist %>' + dest: '<%= pkg.config.public %>' } ] } diff --git a/tasks/imagemin.js b/tasks/imagemin.js index fb6fa1d4..5e997068 100644 --- a/tasks/imagemin.js +++ b/tasks/imagemin.js @@ -15,9 +15,9 @@ module.exports = function (grunt) { files: [ { expand: true, - cwd: '<%= pkg.config.source %>/images', + cwd: '<%= pkg.config.site %>/images', src: '{,*/}*.{png,jpg,jpeg,gif}', - dest: '<%= pkg.config.dist %>/images' + dest: '<%= pkg.config.public %>/images' } ] } diff --git a/tasks/jasmine.js b/tasks/jasmine.js index 64776bf1..2e9770af 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -13,18 +13,18 @@ module.exports = function (grunt) { return { dist: { src: [ - 'source/scripts/chartist.core.js', - 'source/scripts/chartist.event.js', - 'source/scripts/chartist.class.js', - 'source/scripts/chartist.base.js', - 'source/scripts/chartist.svg.js', - 'source/scripts/chartist.line.js', - 'source/scripts/chartist.bar.js', - 'source/scripts/chartist.pie.js' + '<%= pkg.config.src %>/core.js', + '<%= pkg.config.src %>/event.js', + '<%= pkg.config.src %>/class.js', + '<%= pkg.config.src %>/base.js', + '<%= pkg.config.src %>/svg.js', + '<%= pkg.config.src %>/types/line.js', + '<%= pkg.config.src %>/types/bar.js', + '<%= pkg.config.src %>/types/pie.js' ], options: { - specs: 'test/spec/**/spec-*.js', - helpers: 'test/spec/**/helper-*.js', + specs: '<%= pkg.config.test %>/spec/**/spec-*.js', + helpers: '<%= pkg.config.test %>/spec/**/helper-*.js', phantomjs: { 'ignore-ssl-errors': true } diff --git a/tasks/jshint.js b/tasks/jshint.js index d04c36c4..20919ca2 100644 --- a/tasks/jshint.js +++ b/tasks/jshint.js @@ -17,13 +17,14 @@ module.exports = function (grunt) { }, all: [ 'Gruntfile.js', - '<%= pkg.config.source %>/scripts/{,*/}*.js' + '<%= pkg.config.src %>/{,*/}*.js', + '<%= pkg.config.site %>/scripts/{,*/}*.js' ], test: { options: { - jshintrc: 'test/.jshintrc' + jshintrc: '<%= pkg.config.test %>/.jshintrc' }, - src: ['test/spec/{,*/}*.js'] + src: ['<%= pkg.config.test %>/spec/{,*/}*.js'] } }; }; diff --git a/tasks/sass.js b/tasks/sass.js index 15eb4741..f2dc2155 100644 --- a/tasks/sass.js +++ b/tasks/sass.js @@ -12,34 +12,48 @@ module.exports = function (grunt) { return { options: { - includePaths: ['<%= pkg.config.source %>/bower_components'], - imagePath: '<%= pkg.config.source %>/images' + includePaths: ['<%= pkg.config.site %>/bower_components'], + imagePath: '<%= pkg.config.site %>/images' }, - dist: { + public: { // without sourcemaps options: { sourceMap: false }, files: [ { expand: true, - cwd: '<%= pkg.config.source %>/styles', + cwd: '<%= pkg.config.site %>/styles', + src: '{,*/}*.{scss,sass}', + ext: '.css', + dest: '<%= pkg.config.tmp %>/styles' + } + ] + }, + dist: { + options: { + sourceMap: true + }, + files: [ + { + expand: true, + cwd: '<%= pkg.config.src %>/styles', src: '{,*/}*.{scss,sass}', ext: '.css', - dest: '.tmp/styles' + dest: '<%= pkg.config.tmp %>/styles' } ] }, - server: { + tmp: { // with sourcemaps options: { sourceMap: true }, files: [ { expand: true, - cwd: '<%= pkg.config.source %>/styles', + cwd: '<%= pkg.config.site %>/styles', src: '{,*/}*.{scss,sass}', ext: '.css', - dest: '.tmp/styles' + dest: '<%= pkg.config.tmp %>/styles' } ] } diff --git a/tasks/svgmin.js b/tasks/svgmin.js index 0af87913..5259d34f 100644 --- a/tasks/svgmin.js +++ b/tasks/svgmin.js @@ -15,9 +15,9 @@ module.exports = function (grunt) { files: [ { expand: true, - cwd: '<%= pkg.config.source %>/images', + cwd: '<%= pkg.config.site %>/images', src: '{,*/}*.svg', - dest: '<%= pkg.config.dist %>/images' + dest: '<%= pkg.config.public %>/images' } ], options: { diff --git a/tasks/uglify.js b/tasks/uglify.js index bc3c56d9..b3db3cbc 100644 --- a/tasks/uglify.js +++ b/tasks/uglify.js @@ -11,14 +11,22 @@ module.exports = function (grunt) { return { - libdist: { + dist: { options: { - banner: '<%= pkg.config.banner %>', //pkg.config.banner, + banner: '<%= pkg.config.banner %>', sourceMap: true, sourceMapIncludeSources: true }, files: { - 'libdist/chartist.min.js': ['libdist/chartist.js'] + '<%= pkg.config.dist %>/chartist.min.js': ['<%= pkg.config.dist %>/chartist.js'] + } + }, + public: { + options: { + banner: '<%= pkg.config.banner %>', + }, + files: { + '<%= pkg.config.public %>/scripts/all.js': ['<%= pkg.config.public %>/scripts/all.js'] } } }; diff --git a/tasks/umd.js b/tasks/umd.js index 4ab8c373..1aa94191 100644 --- a/tasks/umd.js +++ b/tasks/umd.js @@ -11,8 +11,8 @@ module.exports = function (grunt) { return { - libdist: { - src: 'libdist/chartist.js', + dist: { + src: '<%= pkg.config.dist %>/chartist.js', objectToExport: 'Chartist', globalAlias: 'Chartist', indent: ' ' diff --git a/tasks/usemin.js b/tasks/usemin.js index 6f67fabf..bc0d5bbf 100644 --- a/tasks/usemin.js +++ b/tasks/usemin.js @@ -11,10 +11,10 @@ module.exports = function (grunt) { return { - html: ['<%= pkg.config.dist %>/{,*/}*.html'], - css: ['<%= pkg.config.dist %>/styles/{,*/}*.css'], + html: ['<%= pkg.config.public %>/{,*/}*.html'], + css: ['<%= pkg.config.public %>/styles/{,*/}*.css'], options: { - assetsDirs: ['<%= pkg.config.dist %>'], + assetsDirs: ['<%= pkg.config.public %>'], blockReplacements: { js: function (block) { diff --git a/tasks/useminPrepare.js b/tasks/useminPrepare.js index 12c3ffb6..9a12bbe7 100644 --- a/tasks/useminPrepare.js +++ b/tasks/useminPrepare.js @@ -14,8 +14,8 @@ module.exports = function (grunt) { return { options: { - dest: '<%= pkg.config.dist %>' + dest: '<%= pkg.config.public %>' }, - html: '.tmp/index.html' + html: '<%= pkg.config.tmp %>/index.html' } }; diff --git a/tasks/watch.js b/tasks/watch.js index ec090d5b..421df9e3 100644 --- a/tasks/watch.js +++ b/tasks/watch.js @@ -12,27 +12,33 @@ module.exports = function (grunt) { return { assemble: { - files: ['<%= pkg.config.source %>/site/**/*.{hbs,yml,json,js}'], + files: ['<%= pkg.config.site %>/**/*.{hbs,yml,json,js}'], tasks: ['doxication', 'assemble'] }, doxication: { - files: ['.tmp/data/**/*.{yml,json}'], + files: ['<%= pkg.config.tmp %>/data/**/*.{yml,json}'], tasks: ['doxication', 'assemble'] }, js: { - files: ['<%= pkg.config.source %>/scripts/{,*/}*.js'], + files: [ + '<%= pkg.config.site %>/scripts/{,*/}*.js', + '<%= pkg.config.src %>/{,*/}*.js' + ], tasks: ['newer:jshint:all'], options: { livereload: true } }, jsTest: { - files: ['test/spec/{,*/}*.js'], + files: ['<%= pkg.config.test %>/spec/{,*/}*.js'], tasks: ['newer:jshint:test', 'jasmine'] }, sass: { - files: ['<%= pkg.config.source %>/styles/**/*.{scss,sass}'], - tasks: ['sass:server'] + files: [ + '<%= pkg.config.site %>/styles/{,*/}*.{scss,sass}', + '<%= pkg.config.src %>/styles/{,*/}*.{scss,sass}' + ], + tasks: ['sass:public'] }, gruntfile: { files: ['Gruntfile.js'] @@ -42,9 +48,9 @@ module.exports = function (grunt) { livereload: '<%= connect.options.livereload %>' }, files: [ - '.tmp/{,*/}*.html', - '.tmp/styles/{,*/}*.css', - '<%= pkg.config.source %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' + '<%= pkg.config.tmp %>/{,*/}*.html', + '<%= pkg.config.tmp %>/styles/{,*/}*.css', + '<%= pkg.config.site %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' ] } }; From 3f76c5187274b457daf386ee67b02501ecdb345d Mon Sep 17 00:00:00 2001 From: Autarc Date: Tue, 25 Nov 2014 09:53:08 +0100 Subject: [PATCH 096/593] update configuration files --- .bowerrc | 2 +- .gitignore | 17 +++++++++++++---- bower.json | 8 ++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.bowerrc b/.bowerrc index 466a5a7e..54655825 100644 --- a/.bowerrc +++ b/.bowerrc @@ -1,3 +1,3 @@ { - "directory": "source/bower_components" + "directory": "site/bower_components" } diff --git a/.gitignore b/.gitignore index 6e524438..fb8f6a1f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,14 @@ -node_modules -sitedist -.tmp +# modules +node_modules/ +site/bower_components/ + +# build +.tmp/ +.public/ +# dist/ + +# generated .sass-cache -source/bower_components + +# debug +npm-debug.log diff --git a/bower.json b/bower.json index d91474ba..54198425 100644 --- a/bower.json +++ b/bower.json @@ -2,8 +2,8 @@ "name": "chartist", "version": "0.4.1", "main": [ - "./libdist/chartist.min.js", - "./libdist/chartist.min.css" + "./dist/chartist.min.js", + "./dist/chartist.min.css" ], "devDependencies": { "snap.svg": "~0.2.0", @@ -18,8 +18,8 @@ "Gruntfile.js", "package.json", "node_modules", - "sitedist", - "source", + "public", + "src", "test" ] } From 53a771cbb570fbddcb44cc100384bcd4dd53b5b1 Mon Sep 17 00:00:00 2001 From: Autarc Date: Tue, 25 Nov 2014 09:57:36 +0100 Subject: [PATCH 097/593] add changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..883f9ad4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +v0.4.1 - Tue, 25 Nov 2014 +------------------------- + +- [fe847c8](../../commit/fe847c8) [changed] - organize source files +- [f0cd456](../../commit/f0cd456) [changed] - extract site sources From c13564e6e0ad91618de3926276cfa6b028606053 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 11:16:24 +0100 Subject: [PATCH 098/593] Moved assemble resources out of template folder --- .../code-snippets/aspect-ratio-container.html | 0 .../code-snippets/custom-include.scss | 0 .../simple-start-aspect-ratio-chart.js | 0 .../code-snippets/simple-start-cdn.html | 0 .../code-snippets/simple-start-fixed-chart.js | 0 .../code-snippets/simple-start.html | 0 site/{templates => }/data/pages/examples.yml | 0 .../data/pages/getting-started.yml | 0 site/{templates => }/data/pages/index.yml | 0 .../helpers/chartist-helpers.js | 0 .../{templates => }/helpers/common-helpers.js | 0 site/{templates => }/helpers/dox-helpers.js | 0 site/{templates => }/helpers/lorem-helper.js | 0 site/{templates => }/layouts/content.hbs | 0 site/{templates => }/layouts/default.hbs | 0 site/{templates => }/layouts/landing.hbs | 0 .../partials/api-side-navigation.hbs | 0 .../partials/browser-support-table.hbs | 0 .../{templates => }/partials/code-snippet.hbs | 0 site/{templates => }/partials/code.hbs | 0 .../partials/dox/dox-member.hbs | 0 .../partials/dox/dox-module.hbs | 0 .../partials/dox/dox-section.hbs | 0 .../partials/example-chart.hbs | 0 site/{templates => }/partials/heading.hbs | 0 site/{templates => }/partials/hint.hbs | 0 .../{templates => }/partials/live-example.hbs | 0 site/{templates => }/partials/navigation.hbs | 0 site/{templates => }/partials/section.hbs | 0 .../partials/side-navigation.hbs | 0 site/{templates => }/partials/sub-section.hbs | 0 site/{templates => }/partials/table.hbs | 0 site/{templates => }/partials/text.hbs | 0 site/styles/_modules.scss | 5 +- {src => site}/styles/modules/_animation.scss | 0 {src => site}/styles/modules/_common.scss | 0 {src => site}/styles/modules/_scale.scss | 0 .../examples/behavior-with-jquery.js | 47 ------- .../examples/bi-polar-bar-interpolated.js | 18 --- .../example-bar-with-circle-modify-drawing.js | 28 ---- .../examples/example-bipolar-line-area.js | 19 --- .../examples/example-gallery-four.js | 33 ----- .../templates/examples/example-gallery-one.js | 11 -- .../examples/example-gallery-three.js | 40 ------ .../templates/examples/example-gallery-two.js | 13 -- site/templates/examples/example-line-area.js | 9 -- .../examples/example-line-modify-drawing.js | 30 ----- .../example-line-months-interpolation.js | 28 ---- .../example-line-simple-responsive.js | 41 ------ .../examples/example-line-svg-animation.js | 127 ------------------ .../examples/example-multiline-bar.js | 20 --- site/templates/examples/example-simple-bar.js | 32 ----- .../examples/example-simple-svg-animation.js | 63 --------- .../templates/examples/line-scatter-random.js | 36 ----- site/templates/examples/overlapping-bars.js | 24 ---- .../examples/pie-with-custom-labels.js | 27 ---- .../examples/simple-configuration-chart.js | 38 ------ site/templates/examples/simple-gauge-chart.js | 9 -- site/templates/examples/simple-line-chart.js | 8 -- site/templates/examples/simple-pie-chart.js | 11 -- src/styles/_modules.scss | 5 - src/styles/chartist.scss | 1 - tasks/assemble.js | 8 +- 63 files changed, 8 insertions(+), 723 deletions(-) rename site/{templates => }/code-snippets/aspect-ratio-container.html (100%) rename site/{templates => }/code-snippets/custom-include.scss (100%) rename site/{templates => }/code-snippets/simple-start-aspect-ratio-chart.js (100%) rename site/{templates => }/code-snippets/simple-start-cdn.html (100%) rename site/{templates => }/code-snippets/simple-start-fixed-chart.js (100%) rename site/{templates => }/code-snippets/simple-start.html (100%) rename site/{templates => }/data/pages/examples.yml (100%) rename site/{templates => }/data/pages/getting-started.yml (100%) rename site/{templates => }/data/pages/index.yml (100%) rename site/{templates => }/helpers/chartist-helpers.js (100%) rename site/{templates => }/helpers/common-helpers.js (100%) rename site/{templates => }/helpers/dox-helpers.js (100%) rename site/{templates => }/helpers/lorem-helper.js (100%) rename site/{templates => }/layouts/content.hbs (100%) rename site/{templates => }/layouts/default.hbs (100%) rename site/{templates => }/layouts/landing.hbs (100%) rename site/{templates => }/partials/api-side-navigation.hbs (100%) rename site/{templates => }/partials/browser-support-table.hbs (100%) rename site/{templates => }/partials/code-snippet.hbs (100%) rename site/{templates => }/partials/code.hbs (100%) rename site/{templates => }/partials/dox/dox-member.hbs (100%) rename site/{templates => }/partials/dox/dox-module.hbs (100%) rename site/{templates => }/partials/dox/dox-section.hbs (100%) rename site/{templates => }/partials/example-chart.hbs (100%) rename site/{templates => }/partials/heading.hbs (100%) rename site/{templates => }/partials/hint.hbs (100%) rename site/{templates => }/partials/live-example.hbs (100%) rename site/{templates => }/partials/navigation.hbs (100%) rename site/{templates => }/partials/section.hbs (100%) rename site/{templates => }/partials/side-navigation.hbs (100%) rename site/{templates => }/partials/sub-section.hbs (100%) rename site/{templates => }/partials/table.hbs (100%) rename site/{templates => }/partials/text.hbs (100%) rename {src => site}/styles/modules/_animation.scss (100%) rename {src => site}/styles/modules/_common.scss (100%) rename {src => site}/styles/modules/_scale.scss (100%) delete mode 100644 site/templates/examples/behavior-with-jquery.js delete mode 100644 site/templates/examples/bi-polar-bar-interpolated.js delete mode 100644 site/templates/examples/example-bar-with-circle-modify-drawing.js delete mode 100644 site/templates/examples/example-bipolar-line-area.js delete mode 100644 site/templates/examples/example-gallery-four.js delete mode 100644 site/templates/examples/example-gallery-one.js delete mode 100644 site/templates/examples/example-gallery-three.js delete mode 100644 site/templates/examples/example-gallery-two.js delete mode 100644 site/templates/examples/example-line-area.js delete mode 100644 site/templates/examples/example-line-modify-drawing.js delete mode 100644 site/templates/examples/example-line-months-interpolation.js delete mode 100644 site/templates/examples/example-line-simple-responsive.js delete mode 100644 site/templates/examples/example-line-svg-animation.js delete mode 100644 site/templates/examples/example-multiline-bar.js delete mode 100644 site/templates/examples/example-simple-bar.js delete mode 100644 site/templates/examples/example-simple-svg-animation.js delete mode 100644 site/templates/examples/line-scatter-random.js delete mode 100644 site/templates/examples/overlapping-bars.js delete mode 100644 site/templates/examples/pie-with-custom-labels.js delete mode 100644 site/templates/examples/simple-configuration-chart.js delete mode 100644 site/templates/examples/simple-gauge-chart.js delete mode 100644 site/templates/examples/simple-line-chart.js delete mode 100644 site/templates/examples/simple-pie-chart.js delete mode 100644 src/styles/_modules.scss diff --git a/site/templates/code-snippets/aspect-ratio-container.html b/site/code-snippets/aspect-ratio-container.html similarity index 100% rename from site/templates/code-snippets/aspect-ratio-container.html rename to site/code-snippets/aspect-ratio-container.html diff --git a/site/templates/code-snippets/custom-include.scss b/site/code-snippets/custom-include.scss similarity index 100% rename from site/templates/code-snippets/custom-include.scss rename to site/code-snippets/custom-include.scss diff --git a/site/templates/code-snippets/simple-start-aspect-ratio-chart.js b/site/code-snippets/simple-start-aspect-ratio-chart.js similarity index 100% rename from site/templates/code-snippets/simple-start-aspect-ratio-chart.js rename to site/code-snippets/simple-start-aspect-ratio-chart.js diff --git a/site/templates/code-snippets/simple-start-cdn.html b/site/code-snippets/simple-start-cdn.html similarity index 100% rename from site/templates/code-snippets/simple-start-cdn.html rename to site/code-snippets/simple-start-cdn.html diff --git a/site/templates/code-snippets/simple-start-fixed-chart.js b/site/code-snippets/simple-start-fixed-chart.js similarity index 100% rename from site/templates/code-snippets/simple-start-fixed-chart.js rename to site/code-snippets/simple-start-fixed-chart.js diff --git a/site/templates/code-snippets/simple-start.html b/site/code-snippets/simple-start.html similarity index 100% rename from site/templates/code-snippets/simple-start.html rename to site/code-snippets/simple-start.html diff --git a/site/templates/data/pages/examples.yml b/site/data/pages/examples.yml similarity index 100% rename from site/templates/data/pages/examples.yml rename to site/data/pages/examples.yml diff --git a/site/templates/data/pages/getting-started.yml b/site/data/pages/getting-started.yml similarity index 100% rename from site/templates/data/pages/getting-started.yml rename to site/data/pages/getting-started.yml diff --git a/site/templates/data/pages/index.yml b/site/data/pages/index.yml similarity index 100% rename from site/templates/data/pages/index.yml rename to site/data/pages/index.yml diff --git a/site/templates/helpers/chartist-helpers.js b/site/helpers/chartist-helpers.js similarity index 100% rename from site/templates/helpers/chartist-helpers.js rename to site/helpers/chartist-helpers.js diff --git a/site/templates/helpers/common-helpers.js b/site/helpers/common-helpers.js similarity index 100% rename from site/templates/helpers/common-helpers.js rename to site/helpers/common-helpers.js diff --git a/site/templates/helpers/dox-helpers.js b/site/helpers/dox-helpers.js similarity index 100% rename from site/templates/helpers/dox-helpers.js rename to site/helpers/dox-helpers.js diff --git a/site/templates/helpers/lorem-helper.js b/site/helpers/lorem-helper.js similarity index 100% rename from site/templates/helpers/lorem-helper.js rename to site/helpers/lorem-helper.js diff --git a/site/templates/layouts/content.hbs b/site/layouts/content.hbs similarity index 100% rename from site/templates/layouts/content.hbs rename to site/layouts/content.hbs diff --git a/site/templates/layouts/default.hbs b/site/layouts/default.hbs similarity index 100% rename from site/templates/layouts/default.hbs rename to site/layouts/default.hbs diff --git a/site/templates/layouts/landing.hbs b/site/layouts/landing.hbs similarity index 100% rename from site/templates/layouts/landing.hbs rename to site/layouts/landing.hbs diff --git a/site/templates/partials/api-side-navigation.hbs b/site/partials/api-side-navigation.hbs similarity index 100% rename from site/templates/partials/api-side-navigation.hbs rename to site/partials/api-side-navigation.hbs diff --git a/site/templates/partials/browser-support-table.hbs b/site/partials/browser-support-table.hbs similarity index 100% rename from site/templates/partials/browser-support-table.hbs rename to site/partials/browser-support-table.hbs diff --git a/site/templates/partials/code-snippet.hbs b/site/partials/code-snippet.hbs similarity index 100% rename from site/templates/partials/code-snippet.hbs rename to site/partials/code-snippet.hbs diff --git a/site/templates/partials/code.hbs b/site/partials/code.hbs similarity index 100% rename from site/templates/partials/code.hbs rename to site/partials/code.hbs diff --git a/site/templates/partials/dox/dox-member.hbs b/site/partials/dox/dox-member.hbs similarity index 100% rename from site/templates/partials/dox/dox-member.hbs rename to site/partials/dox/dox-member.hbs diff --git a/site/templates/partials/dox/dox-module.hbs b/site/partials/dox/dox-module.hbs similarity index 100% rename from site/templates/partials/dox/dox-module.hbs rename to site/partials/dox/dox-module.hbs diff --git a/site/templates/partials/dox/dox-section.hbs b/site/partials/dox/dox-section.hbs similarity index 100% rename from site/templates/partials/dox/dox-section.hbs rename to site/partials/dox/dox-section.hbs diff --git a/site/templates/partials/example-chart.hbs b/site/partials/example-chart.hbs similarity index 100% rename from site/templates/partials/example-chart.hbs rename to site/partials/example-chart.hbs diff --git a/site/templates/partials/heading.hbs b/site/partials/heading.hbs similarity index 100% rename from site/templates/partials/heading.hbs rename to site/partials/heading.hbs diff --git a/site/templates/partials/hint.hbs b/site/partials/hint.hbs similarity index 100% rename from site/templates/partials/hint.hbs rename to site/partials/hint.hbs diff --git a/site/templates/partials/live-example.hbs b/site/partials/live-example.hbs similarity index 100% rename from site/templates/partials/live-example.hbs rename to site/partials/live-example.hbs diff --git a/site/templates/partials/navigation.hbs b/site/partials/navigation.hbs similarity index 100% rename from site/templates/partials/navigation.hbs rename to site/partials/navigation.hbs diff --git a/site/templates/partials/section.hbs b/site/partials/section.hbs similarity index 100% rename from site/templates/partials/section.hbs rename to site/partials/section.hbs diff --git a/site/templates/partials/side-navigation.hbs b/site/partials/side-navigation.hbs similarity index 100% rename from site/templates/partials/side-navigation.hbs rename to site/partials/side-navigation.hbs diff --git a/site/templates/partials/sub-section.hbs b/site/partials/sub-section.hbs similarity index 100% rename from site/templates/partials/sub-section.hbs rename to site/partials/sub-section.hbs diff --git a/site/templates/partials/table.hbs b/site/partials/table.hbs similarity index 100% rename from site/templates/partials/table.hbs rename to site/partials/table.hbs diff --git a/site/templates/partials/text.hbs b/site/partials/text.hbs similarity index 100% rename from site/templates/partials/text.hbs rename to site/partials/text.hbs diff --git a/site/styles/_modules.scss b/site/styles/_modules.scss index 28a0babb..45f60fac 100644 --- a/site/styles/_modules.scss +++ b/site/styles/_modules.scss @@ -1,2 +1,5 @@ @import "http://github.com/modules/font"; -@import "http://github.com/modules/icon"; \ No newline at end of file +@import "http://github.com/modules/icon"; +@import "http://github.com/modules/animation"; +@import "http://github.com/modules/common"; +@import "http://github.com/modules/scale"; diff --git a/src/styles/modules/_animation.scss b/site/styles/modules/_animation.scss similarity index 100% rename from src/styles/modules/_animation.scss rename to site/styles/modules/_animation.scss diff --git a/src/styles/modules/_common.scss b/site/styles/modules/_common.scss similarity index 100% rename from src/styles/modules/_common.scss rename to site/styles/modules/_common.scss diff --git a/src/styles/modules/_scale.scss b/site/styles/modules/_scale.scss similarity index 100% rename from src/styles/modules/_scale.scss rename to site/styles/modules/_scale.scss diff --git a/site/templates/examples/behavior-with-jquery.js b/site/templates/examples/behavior-with-jquery.js deleted file mode 100644 index a79cafcb..00000000 --- a/site/templates/examples/behavior-with-jquery.js +++ /dev/null @@ -1,47 +0,0 @@ -new Chartist.Line('.ct-chart', { - labels: ['1', '2', '3', '4', '5', '6'], - series: [ - { - name: 'Fibonacci sequence', - data: [1, 2, 3, 5, 8, 13] - }, - { - name: 'Golden section', - data: [1, 1.618, 2.618, 4.236, 6.854, 11.09] - } - ] -}); - -var easeOutQuad = function (x, t, b, c, d) { - return -c * (t /= d) * (t - 2) + b; -}; - -var $chart = $('.ct-chart'); - -var $toolTip = $chart - .append('
    ') - .find('.tooltip') - .hide(); - -$chart.on('mouseenter', '.ct-point', function() { - var $point = $(this), - value = $point.attr('ct:value'), - seriesName = $point.parent().attr('ct:series-name'); - - $point.animate({'stroke-width': '50px'}, 300, easeOutQuad); - $toolTip.html(seriesName + '
    ' + value).show(); -}); - -$chart.on('mouseleave', '.ct-point', function() { - var $point = $(this); - - $point.animate({'stroke-width': '20px'}, 300, easeOutQuad); - $toolTip.hide(); -}); - -$chart.on('mousemove', function(event) { - $toolTip.css({ - left: event.offsetX - $toolTip.width() / 2 - 10, - top: event.offsetY - $toolTip.height() - 40 - }); -}); \ No newline at end of file diff --git a/site/templates/examples/bi-polar-bar-interpolated.js b/site/templates/examples/bi-polar-bar-interpolated.js deleted file mode 100644 index e9c1da8e..00000000 --- a/site/templates/examples/bi-polar-bar-interpolated.js +++ /dev/null @@ -1,18 +0,0 @@ -var data = { - labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'], - series: [ - [1, 2, 4, 8, 6, -2, -1, -4, -6, -2] - ] -}; - -var options = { - high: 10, - low: -10, - axisX: { - labelInterpolationFnc: function(value, index) { - return index % 2 === 0 ? value : null; - } - } -}; - -new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file diff --git a/site/templates/examples/example-bar-with-circle-modify-drawing.js b/site/templates/examples/example-bar-with-circle-modify-drawing.js deleted file mode 100644 index a5b71c4b..00000000 --- a/site/templates/examples/example-bar-with-circle-modify-drawing.js +++ /dev/null @@ -1,28 +0,0 @@ -// Create a simple bi-polar bar chart -var chart = new Chartist.Bar('.ct-chart', { - labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'], - series: [ - [1, 2, 4, 8, 6, -2, -1, -4, -6, -2] - ] -}, { - high: 10, - low: -10, - axisX: { - labelInterpolationFnc: function(value, index) { - return index % 2 === 0 ? value : null; - } - } -}); - -// Listen for draw events on the bar chart -chart.on('draw', function(data) { - // If this draw event is of type bar we can use the data to create additional content - if(data.type === 'bar') { - // We use the group element of the current series to append a simple circle with the bar peek coordinates and a circle radius that is depending on the value - data.group.append(new Chartist.Svg('circle', { - cx: data.x2, - cy: data.y2, - r: Math.abs(data.value) * 2 + 5 - }, 'ct-slice')); - } -}); diff --git a/site/templates/examples/example-bipolar-line-area.js b/site/templates/examples/example-bipolar-line-area.js deleted file mode 100644 index 03cd06fc..00000000 --- a/site/templates/examples/example-bipolar-line-area.js +++ /dev/null @@ -1,19 +0,0 @@ -new Chartist.Line('.ct-chart', { - labels: [1, 2, 3, 4, 5, 6, 7, 8], - series: [ - [1, 2, 3, 1, -2, 0, 1, 0], - [-2, -1, -2, -1, -2.5, -1, -2, -1], - [0, 0, 0, 1, 2, 2.5, 2, 1], - [2.5, 2, 1, 0.5, 1, 0.5, -1, -2.5] - ] -}, { - high: 3, - low: -3, - showArea: true, - showLine: false, - showPoint: false, - axisX: { - showLabel: false, - showGrid: false - } -}); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-four.js b/site/templates/examples/example-gallery-four.js deleted file mode 100644 index f2a5f704..00000000 --- a/site/templates/examples/example-gallery-four.js +++ /dev/null @@ -1,33 +0,0 @@ -var data = { - series: [60, 20] -}; - -var options = { - donut: true, - donutWidth: 40, - total: 100, - labelInterpolationFnc: function(value) { - return value + '%'; - } -}; - -var responsiveOptions = [ - [ - Foundation.media_queries.medium, - { - labelOffset: 30, - chartPadding: 10, - labelDirection: 'explode' - } - ], - [ - Foundation.media_queries.large, - { - labelOffset: -30, - chartPadding: 0, - labelDirection: 'implode' - } - ] -]; - -new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-one.js b/site/templates/examples/example-gallery-one.js deleted file mode 100644 index daeb09ea..00000000 --- a/site/templates/examples/example-gallery-one.js +++ /dev/null @@ -1,11 +0,0 @@ -var data = { - labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9'], - series: [ - [12, 9, 7, 8, 6, 4, 3, 2, 0], - [2, 1, 3.5, 7, 9, 8, 7.7, 4, 7], - [1, 3, 4, 5, 6, 8, 9, 10, 11], - [11, 7.5, 5.5, 5.5, 4, 3.5, 2, 1, 0] - ] -}; - -new Chartist.Line('.ct-chart', data); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-three.js b/site/templates/examples/example-gallery-three.js deleted file mode 100644 index 631f693f..00000000 --- a/site/templates/examples/example-gallery-three.js +++ /dev/null @@ -1,40 +0,0 @@ -var data = { - labels: ['Day one', 'Day two', 'Day three', 'Day four'], - series: [20, 15, 40, 10] -}; - -var options = { - labelInterpolationFnc: function(value) { - return value.split(/\s+/).reduce(function(str, elem) { - return str + elem[0] + '.'; - }, ''); - } -}; - -var responsiveOptions = [ - [ - Foundation.media_queries.medium, - { - chartPadding: 30, - labelOffset: 50, - labelDirection: 'explode', - labelInterpolationFnc: function(value) { - return value; - } - } - ], - [ - Foundation.media_queries.large, - { - labelOffset: 80 - } - ], - [ - Foundation.media_queries.xlarge, - { - labelOffset: 100 - } - ] -]; - -new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-gallery-two.js b/site/templates/examples/example-gallery-two.js deleted file mode 100644 index e408db59..00000000 --- a/site/templates/examples/example-gallery-two.js +++ /dev/null @@ -1,13 +0,0 @@ -var data = { - labels: ['1938', '1939', '1940', '1941', '1942', '1943'], - series: [ - [12000, 9000, 7000, 8000, 12000, 10000], - [2000, 1000, 3500, 7000, 5000, 9000] - ] -}; - -var options = { - seriesBarDistance: 5 -}; - -new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file diff --git a/site/templates/examples/example-line-area.js b/site/templates/examples/example-line-area.js deleted file mode 100644 index ab86b923..00000000 --- a/site/templates/examples/example-line-area.js +++ /dev/null @@ -1,9 +0,0 @@ -new Chartist.Line('.ct-chart', { - labels: [1, 2, 3, 4, 5, 6, 7, 8], - series: [ - [5, 9, 7, 8, 5, 3, 5, 4] - ] -}, { - low: 0, - showArea: true -}); \ No newline at end of file diff --git a/site/templates/examples/example-line-modify-drawing.js b/site/templates/examples/example-line-modify-drawing.js deleted file mode 100644 index 32785ab1..00000000 --- a/site/templates/examples/example-line-modify-drawing.js +++ /dev/null @@ -1,30 +0,0 @@ -var chart = new Chartist.Line('.ct-chart', { - labels: [1, 2, 3, 4, 5], - series: [ - [12, 9, 7, 8, 5] - ] -}); - -// Listening for draw events that get emitted by the Chartist chart -chart.on('draw', function(data) { - // If the draw event was triggered from drawing a point on the line chart - if(data.type === 'point') { - // We are creating a new path SVG element that draws a triangle around the point coordinates - var triangle = new Chartist.Svg('path', { - d: ['M', - data.x, - data.y - 15, - 'L', - data.x - 15, - data.y + 8, - 'L', - data.x + 15, - data.y + 8, - 'z'].join(' '), - style: 'fill-opacity: 1' - }, 'ct-area'); - - // With data.element we get the Chartist SVG wrapper and we can replace the original point drawn by Chartist with our newly created triangle - data.element.replace(triangle); - } -}); diff --git a/site/templates/examples/example-line-months-interpolation.js b/site/templates/examples/example-line-months-interpolation.js deleted file mode 100644 index 3c053bd6..00000000 --- a/site/templates/examples/example-line-months-interpolation.js +++ /dev/null @@ -1,28 +0,0 @@ -var data = { - labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - series: [ - [1, 2, 2.7, 0, 3, 5, 3, 4, 8, 10, 12, 7], - [0, 1.2, 2, 7, 2.5, 9, 5, 8, 9, 11, 14, 4], - [10, 9, 8, 6.5, 6.8, 6, 5.4, 5.3, 4.5, 4.4, 3, 2.8] - ] -}; - -var responsiveOptions = [ - [ - Foundation.media_queries.small, - { - axisX: { - labelInterpolationFnc: function (value, index) { - // Interpolation function causes only every 2nd label to be displayed - if (index % 2 !== 0) { - return false; - } else { - return value; - } - } - } - } - ] -]; - -new Chartist.Line('.ct-chart', data, null, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-line-simple-responsive.js b/site/templates/examples/example-line-simple-responsive.js deleted file mode 100644 index 62f98744..00000000 --- a/site/templates/examples/example-line-simple-responsive.js +++ /dev/null @@ -1,41 +0,0 @@ -/* Add a basic data series with six labels and values */ -var data = { - labels: ['1', '2', '3', '4', '5', '6'], - series: [ - { - data: [1, 2, 3, 5, 8, 13] - } - ] -}; - -/* Set some base options (settings will override the default settings in Chartist.js *see default settings*). We are adding a basic label interpolation function for the xAxis labels. */ -var options = { - axisX: { - labelInterpolationFnc: function(value) { - return 'Calendar Week ' + value; - } - } -}; - -/* Now we can specify multiple responsive settings that will override the base settings based on order and if the media queries match. In this example we are changing the visibility of dots and lines as well as use different label interpolations for space reasons. */ -var responsiveOptions = [ - ['screen and (min-width: 641px) and (max-width: 1024px)', { - showPoint: false, - axisX: { - labelInterpolationFnc: function(value) { - return 'Week ' + value; - } - } - }], - ['screen and (max-width: 640px)', { - showLine: false, - axisX: { - labelInterpolationFnc: function(value) { - return 'W' + value; - } - } - }] -]; - -/* Initialize the chart with the above settings */ -new Chartist.Line('#my-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-line-svg-animation.js b/site/templates/examples/example-line-svg-animation.js deleted file mode 100644 index 0e344de6..00000000 --- a/site/templates/examples/example-line-svg-animation.js +++ /dev/null @@ -1,127 +0,0 @@ -var chart = new Chartist.Line('.ct-chart', { - labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], - series: [ - [12, 9, 7, 8, 5, 4, 6, 2, 3, 3, 4, 6], - [4, 5, 3, 7, 3, 5, 5, 3, 4, 4, 5, 5], - [5, 3, 4, 5, 6, 3, 3, 4, 5, 6, 3, 4], - [3, 4, 5, 6, 7, 6, 4, 5, 6, 7, 6, 3] - ] -}, { - low: 0 -}); - -// Let's put a sequence number aside so we can use it in the event callbacks -var seq = 0, - delays = 80, - durations = 500; - -// Once the chart is fully created we reset the sequence -chart.on('created', function() { - seq = 0; -}); - -// On each drawn element by Chartist we use the Chartist.Svg API to trigger SMIL animations -chart.on('draw', function(data) { - seq++; - - if(data.type === 'line') { - // If the drawn element is a line we do a simple opacity fade in. This could also be achieved using CSS3 animations. - data.element.animate({ - opacity: { - // The delay when we like to start the animation - begin: seq * delays + 1000, - // Duration of the animation - dur: durations, - // The value where the animation should start - from: 0, - // The value where it should end - to: 1 - } - }); - } else if(data.type === 'label' && data.axis === 'x') { - data.element.animate({ - y: { - begin: seq * delays, - dur: durations, - from: data.y + 100, - to: data.y, - // We can specify an easing function from Chartist.Svg.Easing - easing: 'easeInOutBack' - } - }); - } else if(data.type === 'label' && data.axis === 'y') { - data.element.animate({ - x: { - begin: seq * delays, - dur: durations, - from: data.x - 100, - to: data.x, - easing: 'easeInOutBack' - } - }); - } else if(data.type === 'point') { - data.element.animate({ - x1: { - begin: seq * delays, - dur: durations, - from: data.x - 10, - to: data.x, - easing: 'easeOutQuart' - }, - x2: { - begin: seq * delays, - dur: durations, - from: data.x - 10, - to: data.x, - easing: 'easeOutQuart' - }, - opacity: { - begin: seq * delays, - dur: durations, - from: 0, - to: 1, - easing: 'easeOutQuart' - } - }); - } else if(data.type === 'grid') { - // Using data.axis we get x or y which we can use to construct our animation definition objects - var pos1Animation = { - begin: seq * delays, - dur: durations, - from: data[data.axis + '1'] - 30, - to: data[data.axis + '1'], - easing: 'easeOutQuart' - }; - - var pos2Animation = { - begin: seq * delays, - dur: durations, - from: data[data.axis + '2'] - 100, - to: data[data.axis + '2'], - easing: 'easeOutQuart' - }; - - var animations = {}; - animations[data.axis + '1'] = pos1Animation; - animations[data.axis + '2'] = pos2Animation; - animations['opacity'] = { - begin: seq * delays, - dur: durations, - from: 0, - to: 1, - easing: 'easeOutQuart' - }; - - data.element.animate(animations); - } -}); - -// For the sake of the example we update the chart every time it's created with a delay of 10 seconds -chart.on('created', function() { - if(window.__exampleAnimateTimeout) { - clearTimeout(window.__exampleAnimateTimeout); - window.__exampleAnimateTimeout = null; - } - window.__exampleAnimateTimeout = setTimeout(chart.update.bind(chart), 12000); -}); - diff --git a/site/templates/examples/example-multiline-bar.js b/site/templates/examples/example-multiline-bar.js deleted file mode 100644 index e71f1642..00000000 --- a/site/templates/examples/example-multiline-bar.js +++ /dev/null @@ -1,20 +0,0 @@ -new Chartist.Bar('.ct-chart', { - labels: ['First quarter of the year', 'Second quarter of the year', 'Third quarter of the year', 'Fourth quarter of the year'], - series: [ - [60000, 40000, 80000, 70000], - [40000, 30000, 70000, 65000], - [8000, 3000, 10000, 6000] - ] -}, { - seriesBarDistance: 10, - axisX: { - offset: 60 - }, - axisY: { - offset: 80, - labelInterpolationFnc: function(value) { - return value + ' CHF' - }, - scaleMinSpace: 15 - } -}); \ No newline at end of file diff --git a/site/templates/examples/example-simple-bar.js b/site/templates/examples/example-simple-bar.js deleted file mode 100644 index f655562c..00000000 --- a/site/templates/examples/example-simple-bar.js +++ /dev/null @@ -1,32 +0,0 @@ -var data = { - labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - series: [ - [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8], - [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4] - ] -}; - -var options = { - seriesBarDistance: 15 -}; - -var responsiveOptions = [ - ['screen and (min-width: 641px) and (max-width: 1024px)', { - seriesBarDistance: 10, - axisX: { - labelInterpolationFnc: function (value) { - return value; - } - } - }], - ['screen and (max-width: 640px)', { - seriesBarDistance: 5, - axisX: { - labelInterpolationFnc: function (value) { - return value[0]; - } - } - }] -]; - -new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/example-simple-svg-animation.js b/site/templates/examples/example-simple-svg-animation.js deleted file mode 100644 index 69a57816..00000000 --- a/site/templates/examples/example-simple-svg-animation.js +++ /dev/null @@ -1,63 +0,0 @@ -var chart = new Chartist.Line('.ct-chart', { - labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], - series: [ - [12, 4, 2, 8, 5, 4, 6, 2, 3, 3, 4, 6], - [4, 8, 9, 3, 7, 2, 10, 5, 8, 1, 7, 10] - ] -}, { - low: 0, - showLine: false, - axisX: { - showLabel: false, - offset: 0 - }, - axisY: { - showLabel: false, - offset: 0 - } -}); - -// Let's put a sequence number aside so we can use it in the event callbacks -var seq = 0; - -// Once the chart is fully created we reset the sequence -chart.on('created', function() { - seq = 0; -}); - -// On each drawn element by Chartist we use the Chartist.Svg API to trigger SMIL animations -chart.on('draw', function(data) { - if(data.type === 'point') { - // If the drawn element is a line we do a simple opacity fade in. This could also be achieved using CSS3 animations. - data.element.animate({ - opacity: { - // The delay when we like to start the animation - begin: seq++ * 80, - // Duration of the animation - dur: 500, - // The value where the animation should start - from: 0, - // The value where it should end - to: 1 - }, - x1: { - begin: seq++ * 80, - dur: 500, - from: data.x - 100, - to: data.x, - // You can specify an easing function name or use easing functions from Chartist.Svg.Easing directly - easing: Chartist.Svg.Easing.easeOutQuart - } - }); - } -}); - -// For the sake of the example we update the chart every time it's created with a delay of 8 seconds -chart.on('created', function() { - if(window.__exampleAnimateTimeout) { - clearTimeout(window.__exampleAnimateTimeout); - window.__exampleAnimateTimeout = null; - } - window.__exampleAnimateTimeout = setTimeout(chart.update.bind(chart), 8000); -}); - diff --git a/site/templates/examples/line-scatter-random.js b/site/templates/examples/line-scatter-random.js deleted file mode 100644 index 593f37e9..00000000 --- a/site/templates/examples/line-scatter-random.js +++ /dev/null @@ -1,36 +0,0 @@ -var times = function(n) { - return Array.apply(null, new Array(n)); -}; - -var data = times(52).map(Math.random).reduce(function(data, rnd, index) { - data.labels.push(index + 1); - data.series.forEach(function(series) { - series.push(Math.random() * 100) - }); - - return data; -}, { - labels: [], - series: times(4).map(function() { return new Array() }) -}); - -var options = { - showLine: false, - axisX: { - labelInterpolationFnc: function(value, index) { - return index % 13 === 0 ? 'W' + value : null; - } - } -}; - -var responsiveOptions = [ - ['screen and (min-width: 640px)', { - axisX: { - labelInterpolationFnc: function(value, index) { - return index % 4 === 0 ? 'W' + value : null; - } - } - }] -]; - -new Chartist.Line('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/overlapping-bars.js b/site/templates/examples/overlapping-bars.js deleted file mode 100644 index a8f16db1..00000000 --- a/site/templates/examples/overlapping-bars.js +++ /dev/null @@ -1,24 +0,0 @@ -var data = { - labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - series: [ - [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8], - [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4] - ] -}; - -var options = { - seriesBarDistance: 10 -}; - -var responsiveOptions = [ - ['screen and (max-width: 640px)', { - seriesBarDistance: 5, - axisX: { - labelInterpolationFnc: function (value) { - return value[0]; - } - } - }] -]; - -new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/pie-with-custom-labels.js b/site/templates/examples/pie-with-custom-labels.js deleted file mode 100644 index 3ddf2c51..00000000 --- a/site/templates/examples/pie-with-custom-labels.js +++ /dev/null @@ -1,27 +0,0 @@ -var data = { - labels: ['Bananas', 'Apples', 'Grapes'], - series: [20, 15, 40] -}; - -var options = { - labelInterpolationFnc: function(value) { - return value[0] - } -}; - -var responsiveOptions = [ - ['screen and (min-width: 640px)', { - chartPadding: 30, - labelOffset: 100, - labelDirection: 'explode', - labelInterpolationFnc: function(value) { - return value; - } - }], - ['screen and (min-width: 1024px)', { - labelOffset: 80, - chartPadding: 20 - }] -]; - -new Chartist.Pie('.ct-chart', data, options, responsiveOptions); \ No newline at end of file diff --git a/site/templates/examples/simple-configuration-chart.js b/site/templates/examples/simple-configuration-chart.js deleted file mode 100644 index 7d3b8ced..00000000 --- a/site/templates/examples/simple-configuration-chart.js +++ /dev/null @@ -1,38 +0,0 @@ -// Our labels and three data series -var data = { - labels: ['Week1', 'Week2', 'Week3', 'Week4', 'Week5', 'Week6'], - series: [ - [5, 4, 3, 7, 5, 10], - [3, 2, 9, 5, 4, 6], - [2, 1, -3, -4, -2, 0] - ] -}; - -// We are setting a few options for our chart and override the defaults -var options = { - // Don't draw the line chart points - showPoint: false, - // Disable line smoothing - lineSmooth: false, - // X-Axis specific configuration - axisX: { - // We can disable the grid for this axis - showGrid: false, - // and also don't show the label - showLabel: false - }, - // Y-Axis specific configuration - axisY: { - // Lets offset the chart a bit from the labels - offset: 40, - // The label interpolation function enables you to modify the values - // used for the labels on each axis. Here we are converting the - // values into million pound. - labelInterpolationFnc: function(value) { - return '$' + value + 'm'; - } - } -}; - -// All you need to do is pass your configuration as third parameter to the chart function -new Chartist.Line('.ct-chart', data, options); \ No newline at end of file diff --git a/site/templates/examples/simple-gauge-chart.js b/site/templates/examples/simple-gauge-chart.js deleted file mode 100644 index c7ffec9c..00000000 --- a/site/templates/examples/simple-gauge-chart.js +++ /dev/null @@ -1,9 +0,0 @@ -new Chartist.Pie('.ct-chart', { - series: [20, 10, 30, 40] -}, { - donut: true, - donutWidth: 60, - startAngle: 270, - total: 200, - showLabel: false -}); \ No newline at end of file diff --git a/site/templates/examples/simple-line-chart.js b/site/templates/examples/simple-line-chart.js deleted file mode 100644 index bffe7c3a..00000000 --- a/site/templates/examples/simple-line-chart.js +++ /dev/null @@ -1,8 +0,0 @@ -new Chartist.Line('.ct-chart', { - labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], - series: [ - [12, 9, 7, 8, 5], - [2, 1, 3.5, 7, 3], - [1, 3, 4, 5, 6] - ] -}); \ No newline at end of file diff --git a/site/templates/examples/simple-pie-chart.js b/site/templates/examples/simple-pie-chart.js deleted file mode 100644 index 3417aa1b..00000000 --- a/site/templates/examples/simple-pie-chart.js +++ /dev/null @@ -1,11 +0,0 @@ -var data = { - series: [5, 3, 4] -}; - -var sum = function(a, b) { return a + b }; - -new Chartist.Pie('.ct-chart', data, { - labelInterpolationFnc: function(value) { - return Math.round(value / data.series.reduce(sum) * 100) + '%'; - } -}); \ No newline at end of file diff --git a/src/styles/_modules.scss b/src/styles/_modules.scss deleted file mode 100644 index 938b5eac..00000000 --- a/src/styles/_modules.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import "http://github.com/modules/common"; -@import "http://github.com/modules/scale"; -@import "http://github.com/modules/animation"; - -// not reuqired, used ? diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index 1b2f8c43..2456997b 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -1,4 +1,3 @@ -@import "http://github.com/modules"; @import "http://github.com/settings/chartist-settings"; @mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) { diff --git a/tasks/assemble.js b/tasks/assemble.js index 2527caba..fe1976ff 100644 --- a/tasks/assemble.js +++ b/tasks/assemble.js @@ -12,13 +12,13 @@ module.exports = function (grunt) { return { options: { - helpers: ['<%= pkg.config.site %>/templates/helpers/**/*.js'], - partials: ['<%= pkg.config.site %>/templates/partials/**/*.hbs'], - layoutdir: '<%= pkg.config.site %>/templates/layouts', + helpers: ['<%= pkg.config.site %>/helpers/**/*.js'], + partials: ['<%= pkg.config.site %>/partials/**/*.hbs'], + layoutdir: '<%= pkg.config.site %>/layouts', layoutext: '.hbs', layout: ['default'], data: [ - '<%= pkg.config.site %>/templates/data/**/*.{json,yml}', + '<%= pkg.config.site %>/data/**/*.{json,yml}', '<%= pkg.config.tmp %>/data/**/*.{json,yml}' ] }, From b666c7e9fcf32faf42b365ad634b068d3fac2a55 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 11:25:42 +0100 Subject: [PATCH 099/593] Switched from doxication to assemble-dox --- package.json | 2 +- site/helpers/dox-helpers.js | 4 ++-- tasks/aliases.yml | 1 - tasks/assemble.js | 7 ++++++- tasks/doxication.js | 24 ------------------------ 5 files changed, 9 insertions(+), 29 deletions(-) delete mode 100644 tasks/doxication.js diff --git a/package.json b/package.json index 60602160..36e1a7a2 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "dependencies": {}, "devDependencies": { "assemble": "~0.4.36", + "assemble-dox": "0.0.2", "grunt": "^0.4.5", "grunt-concurrent": "^1.0.0", "grunt-contrib-clean": "^0.6.0", @@ -50,7 +51,6 @@ "grunt-contrib-uglify": "^0.6.0", "grunt-contrib-watch": "^0.6.1", "grunt-critical": "0.0.3", - "grunt-doxication": "0.0.4", "grunt-newer": "^0.8.0", "grunt-sass": "~0.14.2", "grunt-svgmin": "~0.2.0", diff --git a/site/helpers/dox-helpers.js b/site/helpers/dox-helpers.js index edaf3ea6..a0ee1b00 100644 --- a/site/helpers/dox-helpers.js +++ b/site/helpers/dox-helpers.js @@ -39,7 +39,7 @@ module.exports.register = function (Handlebars, opt, params) { return dox.map(function(doxFile) { return { fileName: path.basename(doxFile.file), - modules: doxFile.dox.reduce(function(arr, doxElement) { + modules: doxFile.comments.reduce(function(arr, doxElement) { var doxModuleName = helpers.doxTagProperty(doxElement, 'module', 'string'); if(doxModuleName) { @@ -47,7 +47,7 @@ module.exports.register = function (Handlebars, opt, params) { name: doxModuleName, description: doxElement.description.summary, isPrivate: doxElement.isPrivate, - members: doxFile.dox.filter(function(doxFilterElement) { + members: doxFile.comments.filter(function(doxFilterElement) { return helpers.doxTagProperty(doxFilterElement, 'memberof', 'string') === doxModuleName; }) }); diff --git a/tasks/aliases.yml b/tasks/aliases.yml index 06a85555..b4b928da 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -22,7 +22,6 @@ build: # prepare the website public: - 'clean:public' - - 'doxication' - 'assemble' - 'useminPrepare' - 'concurrent:public' diff --git a/tasks/assemble.js b/tasks/assemble.js index fe1976ff..8c3e38ce 100644 --- a/tasks/assemble.js +++ b/tasks/assemble.js @@ -20,7 +20,12 @@ module.exports = function (grunt) { data: [ '<%= pkg.config.site %>/data/**/*.{json,yml}', '<%= pkg.config.tmp %>/data/**/*.{json,yml}' - ] + ], + plugins: ['assemble-dox'], + dox: { + sourceFiles: ['<%= pkg.config.src %>/**/*.js'], + contextRoot: 'apidox' + } }, pages: { expand: true, diff --git a/tasks/doxication.js b/tasks/doxication.js deleted file mode 100644 index 126abedd..00000000 --- a/tasks/doxication.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * doxication - * ========== - * - * Generate API documentation data file for usage in assemble. - * - * Link: https://github.com/gionkunz/grunt-doxication - */ - -'use strict'; - -module.exports = function (grunt) { - return { - all: { - options: { - format: 'yml' - }, - src: [ - '<%= pkg.config.src %>/{,*/}*.js' - ], - dest: '<%= pkg.config.tmp %>/data/apidox.yml' - } - }; -}; From 70a984a493a56a412dc0d27ba625c5b5fe2c1fa2 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 11:36:25 +0100 Subject: [PATCH 100/593] dev task does only require assemble and sass:tmp to run before watch --- tasks/aliases.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasks/aliases.yml b/tasks/aliases.yml index b4b928da..06de0a7a 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -44,7 +44,8 @@ test: # local version with livereload dev: - - 'public' + - 'assemble' + - 'sass:tmp' - 'connect:livereload' - 'watch' From fe510efe5ae1072bcb88c0ebbe48b6f584ca4490 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 11:48:11 +0100 Subject: [PATCH 101/593] Changed structure of source script files --- site/layouts/default.hbs | 8 ++++---- src/{ => scripts}/base.js | 0 src/{types => scripts/charts}/bar.js | 0 src/{types => scripts/charts}/line.js | 0 src/{types => scripts/charts}/pie.js | 0 src/{ => scripts}/class.js | 0 src/{ => scripts}/core.js | 0 src/{ => scripts}/event.js | 0 src/{ => scripts}/svg.js | 0 tasks/aliases.yml | 1 - tasks/connect.js | 2 +- 11 files changed, 5 insertions(+), 6 deletions(-) rename src/{ => scripts}/base.js (100%) rename src/{types => scripts/charts}/bar.js (100%) rename src/{types => scripts/charts}/line.js (100%) rename src/{types => scripts/charts}/pie.js (100%) rename src/{ => scripts}/class.js (100%) rename src/{ => scripts}/core.js (100%) rename src/{ => scripts}/event.js (100%) rename src/{ => scripts}/svg.js (100%) diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index a89eaa3b..87d1fe0e 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -36,7 +36,7 @@ ga('send', 'pageview'); - + @@ -56,9 +56,9 @@ - - - + + + diff --git a/src/base.js b/src/scripts/base.js similarity index 100% rename from src/base.js rename to src/scripts/base.js diff --git a/src/types/bar.js b/src/scripts/charts/bar.js similarity index 100% rename from src/types/bar.js rename to src/scripts/charts/bar.js diff --git a/src/types/line.js b/src/scripts/charts/line.js similarity index 100% rename from src/types/line.js rename to src/scripts/charts/line.js diff --git a/src/types/pie.js b/src/scripts/charts/pie.js similarity index 100% rename from src/types/pie.js rename to src/scripts/charts/pie.js diff --git a/src/class.js b/src/scripts/class.js similarity index 100% rename from src/class.js rename to src/scripts/class.js diff --git a/src/core.js b/src/scripts/core.js similarity index 100% rename from src/core.js rename to src/scripts/core.js diff --git a/src/event.js b/src/scripts/event.js similarity index 100% rename from src/event.js rename to src/scripts/event.js diff --git a/src/svg.js b/src/scripts/svg.js similarity index 100% rename from src/svg.js rename to src/scripts/svg.js diff --git a/tasks/aliases.yml b/tasks/aliases.yml index 06de0a7a..763077fe 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -51,6 +51,5 @@ dev: # online version preview: - - 'build' - 'public' - 'connect:public' diff --git a/tasks/connect.js b/tasks/connect.js index 1d8c608c..a96208d5 100644 --- a/tasks/connect.js +++ b/tasks/connect.js @@ -22,7 +22,7 @@ module.exports = function (grunt) { open: true, base: [ '<%= pkg.config.tmp %>', - '<%= pkg.config.src %>', + '<%= pkg.config.src %>/scripts', '<%= pkg.config.site %>' ] } From bad373bd19f969d48237ff017a38b2c6d8fd3804 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 12:00:26 +0100 Subject: [PATCH 102/593] Build after refactoring --- dist/chartist.js | 2661 ----------------------------- dist/chartist.min.js | 2 +- dist/chartist.min.js.map | 2 +- dist/scss/_modules.scss | 5 - dist/scss/chartist.scss | 1 - dist/scss/modules/_animation.scss | 21 - dist/scss/modules/_common.scss | 15 - dist/scss/modules/_scale.scss | 41 - 8 files changed, 2 insertions(+), 2746 deletions(-) delete mode 100644 dist/scss/_modules.scss delete mode 100644 dist/scss/modules/_animation.scss delete mode 100644 dist/scss/modules/_common.scss delete mode 100644 dist/scss/modules/_scale.scss diff --git a/dist/chartist.js b/dist/chartist.js index f3755aad..55b52de4 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -19,2667 +19,6 @@ * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ - /** - * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. - * - * @module Chartist.Core - */ - var Chartist = { - version: '0.4.1' - }; - - (function (window, document, Chartist) { - 'use strict'; - - /** - * Helps to simplify functional style code - * - * @memberof Chartist.Core - * @param {*} n This exact value will be returned by the noop function - * @return {*} The same value that was provided to the n parameter - */ - Chartist.noop = function (n) { - return n; - }; - - /** - * Generates a-z from a number 0 to 26 - * - * @memberof Chartist.Core - * @param {Number} n A number from 0 to 26 that will result in a letter a-z - * @return {String} A character from a-z based on the input number n - */ - Chartist.alphaNumerate = function (n) { - // Limit to a-z - return String.fromCharCode(97 + n % 26); - }; - - // TODO: Make it possible to call extend with var args - /** - * Simple recursive object extend - * - * @memberof Chartist.Core - * @param {Object} target Target object where the source will be merged into - * @param {Object} source This object will be merged into target and then target is returned - * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source - */ - Chartist.extend = function (target, source) { - target = target || {}; - for (var prop in source) { - if (typeof source[prop] === 'object') { - target[prop] = Chartist.extend(target[prop], source[prop]); - } else { - target[prop] = source[prop]; - } - } - return target; - }; - - /** - * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {String|Number} value - * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel - */ - Chartist.stripUnit = function(value) { - if(typeof value === 'string') { - value = value.replace(/[^0-9\+-\.]/g, ''); - } - - return +value; - }; - - /** - * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {Number} value - * @param {String} unit - * @returns {String} Returns the passed number value with unit. - */ - Chartist.ensureUnit = function(value, unit) { - if(typeof value === 'number') { - value = value + unit; - } - - return value; - }; - - /** - * This is a wrapper around document.querySelector that will return the query if it's already of type Node - * - * @memberof Chartist.Core - * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly - * @return {Node} - */ - Chartist.querySelector = function(query) { - return query instanceof Node ? query : document.querySelector(query); - }; - - /** - * Create or reinitialize the SVG element for the chart - * - * @memberof Chartist.Core - * @param {Node} container The containing DOM Node object that will be used to plant the SVG element - * @param {String} width Set the width of the SVG element. Default is 100% - * @param {String} height Set the height of the SVG element. Default is 100% - * @param {String} className Specify a class to be added to the SVG element - * @return {Object} The created/reinitialized SVG element - */ - Chartist.createSvg = function (container, width, height, className) { - var svg; - - width = width || '100%'; - height = height || '100%'; - - svg = container.querySelector('svg'); - if(svg) { - container.removeChild(svg); - } - - // Create svg object with width and height or use 100% as default - svg = new Chartist.Svg('svg').attr({ - width: width, - height: height - }).addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' - }); - - // Add the DOM node to our container - container.appendChild(svg._node); - - return svg; - }; - - /** - * Convert data series into plain array - * - * @memberof Chartist.Core - * @param {Object} data The series object that contains the data to be visualized in the chart - * @return {Array} A plain array that contains the data to be visualized in the chart - */ - Chartist.getDataArray = function (data) { - var array = []; - - for (var i = 0; i < data.series.length; i++) { - // If the series array contains an object with a data property we will use the property - // otherwise the value directly (array or number) - array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? - data.series[i].data : data.series[i]; - - // Convert values to number - for (var j = 0; j < array[i].length; j++) { - array[i][j] = +array[i][j]; - } - } - - return array; - }; - - /** - * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. - * @param {Number} length The length of the x-axis data array. - * @return {Array} The array that got updated with missing values. - */ - Chartist.normalizeDataArray = function (dataArray, length) { - for (var i = 0; i < dataArray.length; i++) { - if (dataArray[i].length === length) { - continue; - } - - for (var j = dataArray[i].length; j < length; j++) { - dataArray[i][j] = 0; - } - } - - return dataArray; - }; - - /** - * Calculate the order of magnitude for the chart scale - * - * @memberof Chartist.Core - * @param {Number} value The value Range of the chart - * @return {Number} The order of magnitude - */ - Chartist.orderOfMagnitude = function (value) { - return Math.floor(Math.log(Math.abs(value)) / Math.LN10); - }; - - /** - * Project a data length into screen coordinates (pixels) - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Number} length Single data value from a series array - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Number} The projected data length in pixels - */ - Chartist.projectLength = function (svg, length, bounds, options) { - var availableHeight = Chartist.getAvailableHeight(svg, options); - return (length / bounds.range * availableHeight); - }; - - /** - * Get the height of the area in the chart for the data series - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Number} The height of the area in the chart for the data series - */ - Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); - }; - - /** - * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart - * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart. - */ - Chartist.getHighLow = function (dataArray) { - var i, - j, - highLow = { - high: -Number.MAX_VALUE, - low: Number.MAX_VALUE - }; - - for (i = 0; i < dataArray.length; i++) { - for (j = 0; j < dataArray[i].length; j++) { - if (dataArray[i][j] > highLow.high) { - highLow.high = dataArray[i][j]; - } - - if (dataArray[i][j] < highLow.low) { - highLow.low = dataArray[i][j]; - } - } - } - - return highLow; - }; - - // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude - /** - * Calculate and retrieve all the bounds for the chart and return them in one array - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Array} normalizedData The array that got updated with missing values. - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Number} referenceValue The reference value for the chart. - * @return {Object} All the values to set the bounds of the chart - */ - Chartist.getBounds = function (svg, normalizedData, options, referenceValue) { - var i, - newMin, - newMax, - bounds = Chartist.getHighLow(normalizedData); - - // Overrides of high / low from settings - bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); - bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); - - // If high and low are the same because of misconfiguration or flat data (only the same value) we need - // to set the high or low to 0 depending on the polarity - if(bounds.high === bounds.low) { - // If both values are 0 we set high to 1 - if(bounds.low === 0) { - bounds.high = 1; - } else if(bounds.low < 0) { - // If we have the same negative value for the bounds we set bounds.high to 0 - bounds.high = 0; - } else { - // If we have the same positive value for the bounds we set bounds.low to 0 - bounds.low = 0; - } - } - - // Overrides of high / low based on reference value, it will make sure that the invisible reference value is - // used to generate the chart. This is useful when the chart always needs to contain the position of the - // invisible reference value in the view i.e. for bipolar scales. - if (referenceValue || referenceValue === 0) { - bounds.high = Math.max(referenceValue, bounds.high); - bounds.low = Math.min(referenceValue, bounds.low); - } - - bounds.valueRange = bounds.high - bounds.low; - bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); - bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.range = bounds.max - bounds.min; - bounds.step = Math.pow(10, bounds.oom); - bounds.numberOfSteps = Math.round(bounds.range / bounds.step); - - // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace - // If we are already below the scaleMinSpace value we will scale up - var length = Chartist.projectLength(svg, bounds.step, bounds, options), - scaleUp = length < options.axisY.scaleMinSpace; - - while (true) { - if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { - bounds.step *= 2; - } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { - bounds.step /= 2; - } else { - break; - } - } - - // Narrow min and max based on new step - newMin = bounds.min; - newMax = bounds.max; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - if (i + bounds.step < bounds.low) { - newMin += bounds.step; - } - - if (i - bounds.step >= bounds.high) { - newMax -= bounds.step; - } - } - bounds.min = newMin; - bounds.max = newMax; - bounds.range = bounds.max - bounds.min; - - bounds.values = []; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - bounds.values.push(i); - } - - return bounds; - }; - - /** - * Calculate cartesian coordinates of polar coordinates - * - * @memberof Chartist.Core - * @param {Number} centerX X-axis coordinates of center point of circle segment - * @param {Number} centerY X-axis coordinates of center point of circle segment - * @param {Number} radius Radius of circle segment - * @param {Number} angleInDegrees Angle of circle segment in degrees - * @return {Number} Coordinates of point on circumference - */ - Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { - var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; - - return { - x: centerX + (radius * Math.cos(angleInRadians)), - y: centerY + (radius * Math.sin(angleInRadians)) - }; - }; - - /** - * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements - */ - Chartist.createChartRect = function (svg, options) { - var yOffset = options.axisY ? options.axisY.offset : 0, - xOffset = options.axisX ? options.axisX.offset : 0; - - return { - x1: options.chartPadding + yOffset, - y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), - y2: options.chartPadding, - width: function () { - return this.x2 - this.x1; - }, - height: function () { - return this.y1 - this.y2; - } - }; - }; - - /** - * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. - * - * @param {Object} parent The SVG element where the label should be created as a child - * @param {String} text The label text - * @param {Object} attributes An object with all attributes that should be set on the label element - * @param {String} className The class names that should be set for this element - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - * @returns {Object} The newly created SVG element - */ - Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { - if(supportsForeignObject) { - var content = '' + text + ''; - return parent.foreignObject(content, attributes); - } else { - return parent.elem('text', attributes, className).text(text); - } - }; - - /** - * Generate grid lines and labels for the x-axis into grid and labels group SVG elements - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} data The Object that contains the data to be visualized in the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create X-Axis - data.labels.forEach(function (value, index) { - var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - width = chartRect.width() / data.labels.length, - height = options.axisX.offset, - pos = chartRect.x1 + width * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { - return; - } - - if (options.axisX.showGrid) { - var gridElement = grid.elem('line', { - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }, [options.classNames.grid, options.classNames.horizontal].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'x', - index: index, - group: grid, - element: gridElement, - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }); - } - - if (options.axisX.showLabel) { - var labelPosition = { - x: pos + options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); - - eventEmitter.emit('draw', { - type: 'label', - axis: 'x', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.width; - } - }); - } - }); - }; - - /** - * Generate grid lines and labels for the y-axis into grid and labels group SVG elements - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create Y-Axis - bounds.values.forEach(function (value, index) { - var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - width = options.axisY.offset, - height = chartRect.height() / bounds.values.length, - pos = chartRect.y1 - height * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { - return; - } - - if (options.axisY.showGrid) { - var gridElement = grid.elem('line', { - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }, [options.classNames.grid, options.classNames.vertical].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'y', - index: index, - group: grid, - element: gridElement, - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }); - } - - if (options.axisY.showLabel) { - var labelPosition = { - x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), - y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); - - eventEmitter.emit('draw', { - type: 'label', - axis: 'y', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.height; - } - }); - } - }); - }; - - /** - * Determine the current point on the svg element to draw the data series - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Number} index The index of the current project point - * @return {Object} The coordinates object of the current project point containing an x and y number property - */ - Chartist.projectPoint = function (chartRect, bounds, data, index) { - return { - x: chartRect.x1 + chartRect.width() / data.length * index, - y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) - }; - }; - - // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one - /** - * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches - * - * @memberof Chartist.Core - * @param {Object} defaultOptions Default options from Chartist - * @param {Object} options Options set by user - * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart - * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events - * @return {Object} The consolidated options object from the defaults, base and matching responsive options - */ - Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions, eventEmitter) { - var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options), - currentOptions, - mediaQueryListeners = [], - i; - - function updateCurrentOptions() { - var previousOptions = currentOptions; - currentOptions = Chartist.extend({}, baseOptions); - - if (responsiveOptions) { - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); - if (mql.matches) { - currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]); - } - } - } - - if(eventEmitter) { - eventEmitter.emit('optionsChanged', { - previousOptions: previousOptions, - currentOptions: currentOptions - }); - } - } - - function removeMediaQueryListeners() { - mediaQueryListeners.forEach(function(mql) { - mql.removeListener(updateCurrentOptions); - }); - } - - if (!window.matchMedia) { - throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; - } else if (responsiveOptions) { - - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); - mql.addListener(updateCurrentOptions); - mediaQueryListeners.push(mql); - } - } - // Execute initially so we get the correct options - updateCurrentOptions(); - - return { - get currentOptions() { - return Chartist.extend({}, currentOptions); - }, - removeMediaQueryListeners: removeMediaQueryListeners - }; - }; - - //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas - /** - * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property - * where deltas for specific object properties can be found for the given object nesting level. For nested objects the - * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also - * contain a __delta__ property with the deltas of their level. - * - * @param {Object|Array} a Object that should be used to analyzed delta to object b - * @param {Object|Array} b The second object where the deltas from a should be analyzed - * @returns {Object} Delta descriptor object or null - */ - Chartist.deltaDescriptor = function(a, b) { - var summary = { - added: 0, - removed: 0, - modified: 0 - }; - - function findDeltasRecursively(a, b) { - var descriptor = { - __delta__: {} - }; - - // First check for removed and modified properties - Object.keys(a).forEach(function(property) { - if(!b.hasOwnProperty(property)) { - descriptor.__delta__[property] = { - type: 'remove', - property: property, - ours: a[property] - }; - summary.removed++; - } else { - if(typeof a[property] === 'object') { - var subDescriptor = findDeltasRecursively(a[property], b[property]); - if(subDescriptor) { - descriptor[property] = subDescriptor; - } - } else { - if(a[property] !== b[property]) { - descriptor.__delta__[property] = { - type: 'modify', - property: property, - ours: a[property], - theirs: b[property] - }; - summary.modified++; - } - } - } - }); - - // Check for added properties - Object.keys(b).forEach(function(property) { - if(!a.hasOwnProperty(property)) { - descriptor.__delta__[property] = { - type: 'added', - property: property, - theirs: b[property] - }; - summary.added++; - } - }); - - return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null; - } - - var delta = findDeltasRecursively(a, b); - if(delta) { - delta.__delta__.summary = summary; - } - - return delta; - }; - - //http://schepers.cc/getting-to-the-point - Chartist.catmullRom2bezier = function (crp, z) { - var d = []; - for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { - var p = [ - {x: +crp[i - 2], y: +crp[i - 1]}, - {x: +crp[i], y: +crp[i + 1]}, - {x: +crp[i + 2], y: +crp[i + 3]}, - {x: +crp[i + 4], y: +crp[i + 5]} - ]; - if (z) { - if (!i) { - p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; - } else if (iLen - 4 === i) { - p[3] = {x: +crp[0], y: +crp[1]}; - } else if (iLen - 2 === i) { - p[2] = {x: +crp[0], y: +crp[1]}; - p[3] = {x: +crp[2], y: +crp[3]}; - } - } else { - if (iLen - 4 === i) { - p[3] = p[2]; - } else if (!i) { - p[0] = {x: +crp[i], y: +crp[i + 1]}; - } - } - d.push( - [ - (-p[0].x + 6 * p[1].x + p[2].x) / 6, - (-p[0].y + 6 * p[1].y + p[2].y) / 6, - (p[1].x + 6 * p[2].x - p[3].x) / 6, - (p[1].y + 6 * p[2].y - p[3].y) / 6, - p[2].x, - p[2].y - ] - ); - } - - return d; - }; - - }(window, document, Chartist)); - ;/** - * A very basic event module that helps to generate and catch events. - * - * @module Chartist.Event - */ - /* global Chartist */ - (function (window, document, Chartist) { - 'use strict'; - - Chartist.EventEmitter = function () { - var handlers = []; - - /** - * Add an event handler for a specific event - * - * @memberof Chartist.Event - * @param {String} event The event name - * @param {Function} handler A event handler function - */ - function addEventHandler(event, handler) { - handlers[event] = handlers[event] || []; - handlers[event].push(handler); - } - - /** - * Remove an event handler of a specific event name or remove all event handlers for a specific event. - * - * @memberof Chartist.Event - * @param {String} event The event name where a specific or all handlers should be removed - * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. - */ - function removeEventHandler(event, handler) { - // Only do something if there are event handlers with this name existing - if(handlers[event]) { - // If handler is set we will look for a specific handler and only remove this - if(handler) { - handlers[event].splice(handlers[event].indexOf(handler), 1); - if(handlers[event].length === 0) { - delete handlers[event]; - } - } else { - // If no handler is specified we remove all handlers for this event - delete handlers[event]; - } - } - } - - /** - * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. - * - * @memberof Chartist.Event - * @param {String} event The event name that should be triggered - * @param {*} data Arbitrary data that will be passed to the event handler callback functions - */ - function emit(event, data) { - // Only do something if there are event handlers with this name existing - if(handlers[event]) { - handlers[event].forEach(function(handler) { - handler(data); - }); - } - - // Emit event to star event handlers - if(handlers['*']) { - handlers['*'].forEach(function(starHandler) { - starHandler(event, data); - }); - } - } - - return { - addEventHandler: addEventHandler, - removeEventHandler: removeEventHandler, - emit: emit - }; - }; - - }(window, document, Chartist)); - ;/** - * This module provides some basic prototype inheritance utilities. - * - * @module Chartist.Class - */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - function listToArray(list) { - var arr = []; - if (list.length) { - for (var i = 0; i < list.length; i++) { - arr.push(list[i]); - } - } - return arr; - } - - /** - * Method to extend from current prototype. - * - * @memberof Chartist.Class - * @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. - * @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. - * @returns {Function} Constructor function of the new class - * - * @example - * var Fruit = Class.extend({ - * color: undefined, - * sugar: undefined, - * - * constructor: function(color, sugar) { - * this.color = color; - * this.sugar = sugar; - * }, - * - * eat: function() { - * this.sugar = 0; - * return this; - * } - * }); - * - * var Banana = Fruit.extend({ - * length: undefined, - * - * constructor: function(length, sugar) { - * Banana.super.constructor.call(this, 'Yellow', sugar); - * this.length = length; - * } - * }); - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - */ - function extend(properties, superProtoOverride) { - var superProto = superProtoOverride || this.prototype || Chartist.Class; - var proto = Object.create(superProto); - - Chartist.Class.cloneDefinitions(proto, properties); - - var constr = function() { - var fn = proto.constructor || function () {}, - instance; - - // If this is linked to the Chartist namespace the constructor was not called with new - // To provide a fallback we will instantiate here and return the instance - instance = this === Chartist ? Object.create(proto) : this; - fn.apply(instance, Array.prototype.slice.call(arguments, 0)); - - // If this constructor was not called with new we need to return the instance - // This will not harm when the constructor has been called with new as the returned value is ignored - return instance; - }; - - constr.prototype = proto; - constr.super = superProto; - constr.extend = this.extend; - - return constr; - } - - /** - * Creates a mixin from multiple super prototypes. - * - * @memberof Chartist.Class - * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. - * @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. - * @returns {Function} Constructor function of the newly created mixin class - * - * @example - * var Fruit = Class.extend({ - * color: undefined, - * sugar: undefined, - * - * constructor: function(color, sugar) { - * this.color = color; - * this.sugar = sugar; - * }, - * - * eat: function() { - * this.sugar = 0; - * return this; - * } - * }); - * - * var Banana = Fruit.extend({ - * length: undefined, - * - * constructor: function(length, sugar) { - * Banana.super.constructor.call(this, 'Yellow', sugar); - * this.length = length; - * } - * }); - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * - * var KCal = Class.extend({ - * sugar: 0, - * - * constructor: function(sugar) { - * this.sugar = sugar; - * }, - * - * get kcal() { - * return [this.sugar * 4, 'kcal'].join(''); - * } - * }); - * - * var Nameable = Class.extend({ - * name: undefined, - * - * constructor: function(name) { - * this.name = name; - * } - * }); - * - * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { - * constructor: function(name, length, sugar) { - * Nameable.prototype.constructor.call(this, name); - * Banana.prototype.constructor.call(this, length, sugar); - * }, - * - * toString: function() { - * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); - * } - * }); - * - * - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); - * console.log(superBanana.toString()); - * - */ - function mix(mixProtoArr, properties) { - if(this !== Chartist.Class) { - throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); - } - - // Make sure our mixin prototypes are the class objects and not the constructors - var superPrototypes = [{}] - .concat(mixProtoArr) - .map(function (prototype) { - return prototype instanceof Function ? prototype.prototype : prototype; - }); - - var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); - // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype - delete mixedSuperProto.constructor; - return this.extend(properties, mixedSuperProto); - } - - // Variable argument list clones args > 0 into args[0] and retruns modified args[0] - function cloneDefinitions() { - var args = listToArray(arguments); - var target = args[0]; - - args.splice(1, args.length - 1).forEach(function (source) { - Object.getOwnPropertyNames(source).forEach(function (propName) { - // If this property already exist in target we delete it first - delete target[propName]; - // Define the property with the descriptor from source - Object.defineProperty(target, propName, - Object.getOwnPropertyDescriptor(source, propName)); - }); - }); - - return target; - } - - Chartist.Class = { - extend: extend, - mix: mix, - cloneDefinitions: cloneDefinitions - }; - - }(window, document, Chartist)); - ;/** - * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. - * - * @module Chartist.Base - */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @memberof Chartist.Base - */ - function update() { - this.createChart(this.optionsProvider.currentOptions); - return this; - } - - /** - * 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. - * - * @memberof Chartist.Base - */ - function detach() { - window.removeEventListener('resize', this.resizeListener); - this.optionsProvider.removeMediaQueryListeners(); - return this; - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Base - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - this.eventEmitter.addEventHandler(event, handler); - return this; - } - - /** - * 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. - * - * @memberof Chartist.Base - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - this.eventEmitter.removeEventHandler(event, handler); - return this; - } - - /** - * Constructor of chart base class. - * - * @param query - * @param data - * @param options - * @param responsiveOptions - * @constructor - */ - function Base(query, data, options, responsiveOptions) { - this.container = Chartist.querySelector(query); - this.data = data; - this.options = options; - this.responsiveOptions = responsiveOptions; - this.eventEmitter = Chartist.EventEmitter(); - this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); - this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); - this.resizeListener = function resizeListener(){ - this.update(); - }.bind(this); - - if(this.container) { - // If chartist was already initialized in this container we are detaching all event listeners first - if(this.container.__chartist__) { - this.container.__chartist__.detach(); - } - - this.container.__chartist__ = this; - } - - window.addEventListener('resize', this.resizeListener); - - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - setTimeout(function() { - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - // TODO: Remove default options parameter from optionsProvider - this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter); - this.createChart(this.optionsProvider.currentOptions); - }.bind(this), 0); - } - - // Creating the chart base class - Chartist.Base = Chartist.Class.extend({ - constructor: Base, - optionsProvider: undefined, - container: undefined, - svg: undefined, - eventEmitter: undefined, - createChart: function() { - throw new Error('Base chart type can\'t be instantiated!'); - }, - update: update, - detach: detach, - on: on, - off: off, - version: Chartist.version, - supportsForeignObject: false - }); - - }(window, document, Chartist)); - ;/** - * Chartist SVG module for simple SVG DOM abstraction - * - * @module Chartist.Svg - */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; - - Chartist.xmlNs = { - qualifiedName: 'xmlns:ct', - prefix: 'ct', - uri: 'http://gionkunz.github.com/chartist-js/ct' - }; - - /** - * 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. - * - * @memberof Chartist.Svg - * @constructor - * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg - * @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. - * @param {String} className This class or class list will be added to the SVG element - * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child - * @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 - */ - function Svg(name, attributes, className, parent, insertFirst) { - // If Svg is getting called with an SVG element we just return the wrapper - if(name instanceof SVGElement) { - this._node = name; - } else { - this._node = document.createElementNS(svgNs, name); - - // If this is an SVG element created then custom namespace - if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); - } - - if(attributes) { - this.attr(attributes); - } - - if(className) { - this.addClass(className); - } - - if(parent) { - if (insertFirst && parent._node.firstChild) { - parent._node.insertBefore(this._node, parent._node.firstChild); - } else { - parent._node.appendChild(this._node); - } - } - } - } - - /** - * Set attributes on the current SVG element of the wrapper you're currently working on. - * - * @memberof Chartist.Svg - * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {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. - */ - function attr(attributes, ns) { - if(typeof attributes === 'string') { - if(ns) { - return this._node.getAttributeNS(ns, attributes); - } else { - return this._node.getAttribute(attributes); - } - } - - Object.keys(attributes).forEach(function(key) { - // If the attribute value is undefined we can skip this one - if(attributes[key] === undefined) { - return; - } - - if(ns) { - this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); - } else { - this._node.setAttribute(key, attributes[key]); - } - }.bind(this)); - - return this; - } - - /** - * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. - * - * @memberof Chartist.Svg - * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @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 - * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data - */ - function elem(name, attributes, className, insertFirst) { - return new Chartist.Svg(name, attributes, className, this, insertFirst); - } - - /** - * Returns the parent Chartist.SVG wrapper object - * - * @returns {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. - */ - function parent() { - return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; - } - - /** - * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. - * - * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element - */ - function root() { - var node = this._node; - while(node.nodeName !== 'svg') { - node = node.parentNode; - } - return new Chartist.Svg(node); - } - - /** - * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. - * - * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found - */ - function querySelector(selector) { - var foundNode = this._node.querySelector(selector); - return foundNode ? new Chartist.Svg(foundNode) : null; - } - - /** - * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. - * - * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found - */ - function querySelectorAll(selector) { - var foundNodes = this._node.querySelectorAll(selector); - return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; - } - - /** - * 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. - * - * @memberof Chartist.Svg - * @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 - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element - */ - function foreignObject(content, attributes, className, insertFirst) { - // If content is string then we convert it to DOM - // TODO: Handle case where content is not a string nor a DOM Node - if(typeof content === 'string') { - var container = document.createElement('div'); - container.innerHTML = content; - content = container.firstChild; - } - - // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); - - // Creating the foreignObject without required extension attribute (as described here - // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = this.elem('foreignObject', attributes, className, insertFirst); - - // Add content to foreignObjectElement - fnObj._node.appendChild(content); - - return fnObj; - } - - /** - * This method adds a new text element to the current Chartist.Svg wrapper. - * - * @memberof Chartist.Svg - * @param {String} t The text that should be added to the text element that is created - * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element - */ - function text(t) { - this._node.appendChild(document.createTextNode(t)); - return this; - } - - /** - * This method will clear all child nodes of the current wrapper object. - * - * @memberof Chartist.Svg - * @returns {Chartist.Svg} The same wrapper object that got emptied - */ - function empty() { - while (this._node.firstChild) { - this._node.removeChild(this._node.firstChild); - } - - return this; - } - - /** - * 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. - * - * @memberof Chartist.Svg - * @returns {Chartist.Svg} The parent wrapper object of the element that got removed - */ - function remove() { - this._node.parentNode.removeChild(this._node); - return new Chartist.Svg(this._node.parentNode); - } - - /** - * This method will replace the element with a new element that can be created outside of the current DOM. - * - * @memberof Chartist.Svg - * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object - * @returns {Chartist.Svg} The wrapper of the new element - */ - function replace(newElement) { - this._node.parentNode.replaceChild(newElement._node, this._node); - return newElement; - } - - /** - * This method will append an element to the current element as a child. - * - * @memberof Chartist.Svg - * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child - * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Chartist.Svg} The wrapper of the appended object - */ - function append(element, insertFirst) { - if(insertFirst && this._node.firstChild) { - this._node.insertBefore(element._node, this._node.firstChild); - } else { - this._node.appendChild(element._node); - } - - return this; - } - - /** - * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. - * - * @memberof Chartist.Svg - * @returns {Array} A list of classes or an empty array if there are no classes on the current element - */ - function classes() { - return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; - } - - /** - * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element - */ - function addClass(names) { - this._node.setAttribute('class', - this.classes(this._node) - .concat(names.trim().split(/\s+/)) - .filter(function(elem, pos, self) { - return self.indexOf(elem) === pos; - }).join(' ') - ); - - return this; - } - - /** - * Removes one or a space separated list of classes from the current element. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element - */ - function removeClass(names) { - var removedClasses = names.trim().split(/\s+/); - - this._node.setAttribute('class', this.classes(this._node).filter(function(name) { - return removedClasses.indexOf(name) === -1; - }).join(' ')); - - return this; - } - - /** - * Removes all classes from the current element. - * - * @memberof Chartist.Svg - * @returns {Chartist.Svg} The wrapper of the current element - */ - function removeAllClasses() { - this._node.setAttribute('class', ''); - - return this; - } - - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Svg - * @return {Number} The elements height in pixels - */ - function height() { - return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; - } - - /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @return {Number} The elements width in pixels - */ - function width() { - return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; - } - - /** - * 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. - * **An animations object could look like this:** - * ```javascript - * element.animate({ - * opacity: { - * dur: 1000, - * from: 0, - * to: 1 - * }, - * x1: { - * dur: '1000ms', - * from: 100, - * to: 200, - * easing: 'easeOutQuart' - * }, - * y1: { - * dur: '2s', - * from: 0, - * to: 100 - * } - * }); - * ``` - * **Automatic unit conversion** - * 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. - * **Guided mode** - * 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. - * If guided mode is enabled the following behavior is added: - * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation - * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) - * - The animate element will be forced to use `fill="freeze"` - * - 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. - * - After the animation the element attribute value will be set to the `to` value of the animation - * - The animate element is deleted from the DOM - * - * @memberof Chartist.Svg - * @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. - * @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. - * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. - * @returns {Chartist.Svg} The current element where the animation was added - */ - function animate(animations, guided, eventEmitter) { - if(guided === undefined) { - guided = true; - } - - Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { - - function createAnimate(animationDefinition, guided) { - var attributeProperties = {}, - animate, - timeout, - easing; - - // Check if an easing is specified in the definition object and delete it from the object as it will not - // be part of the animate element attributes. - if(animationDefinition.easing) { - // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object - easing = animationDefinition.easing instanceof Array ? - animationDefinition.easing : - Chartist.Svg.Easing[animationDefinition.easing]; - delete animationDefinition.easing; - } - - // If numeric dur or begin was provided we assume milli seconds - animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); - animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); - - if(easing) { - animationDefinition.calcMode = 'spline'; - animationDefinition.keySplines = easing.join(' '); - animationDefinition.keyTimes = '0;1'; - } - - // Adding "fill: freeze" if we are in guided mode and set initial attribute values - if(guided) { - animationDefinition.fill = 'freeze'; - // Animated property on our element should already be set to the animation from value in guided mode - attributeProperties[attribute] = animationDefinition.from; - this.attr(attributeProperties); - - // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin - // which needs to be in ms aside - timeout = Chartist.stripUnit(animationDefinition.begin || 0); - animationDefinition.begin = 'indefinite'; - } - - animate = this.elem('animate', Chartist.extend({ - attributeName: attribute - }, animationDefinition)); - - if(guided) { - // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout - setTimeout(function() { - animate._node.beginElement(); - }, timeout); - } - - if(eventEmitter) { - animate._node.addEventListener('beginEvent', function handleBeginEvent() { - eventEmitter.emit('animationBegin', { - element: this, - animate: animate._node, - params: animationDefinition - }); - }.bind(this)); - } - - animate._node.addEventListener('endEvent', function handleEndEvent() { - if(eventEmitter) { - eventEmitter.emit('animationEnd', { - element: this, - animate: animate._node, - params: animationDefinition - }); - } - - if(guided) { - // Set animated attribute to current animated value - attributeProperties[attribute] = animationDefinition.to; - this.attr(attributeProperties); - // Remove the animate element as it's no longer required - animate.remove(); - } - }.bind(this)); - } - - // If current attribute is an array of definition objects we create an animate for each and disable guided mode - if(animations[attribute] instanceof Array) { - animations[attribute].forEach(function(animationDefinition) { - createAnimate.bind(this)(animationDefinition, false); - }.bind(this)); - } else { - createAnimate.bind(this)(animations[attribute], guided); - } - - }.bind(this)); - - return this; - } - - Chartist.Svg = Chartist.Class.extend({ - constructor: Svg, - attr: attr, - elem: elem, - parent: parent, - root: root, - querySelector: querySelector, - querySelectorAll: querySelectorAll, - foreignObject: foreignObject, - text: text, - empty: empty, - remove: remove, - replace: replace, - append: append, - classes: classes, - addClass: addClass, - removeClass: removeClass, - removeAllClasses: removeAllClasses, - height: height, - width: width, - animate: animate - }); - - /** - * 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. - * - * @memberof Chartist.Svg - * @param {String} feature The SVG 1.1 feature that should be checked for support. - * @returns {Boolean} True of false if the feature is supported or not - */ - Chartist.Svg.isSupported = function(feature) { - return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); - }; - - /** - * 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. - * - * @memberof Chartist.Svg - */ - var easingCubicBeziers = { - easeInSine: [0.47, 0, 0.745, 0.715], - easeOutSine: [0.39, 0.575, 0.565, 1], - easeInOutSine: [0.445, 0.05, 0.55, 0.95], - easeInQuad: [0.55, 0.085, 0.68, 0.53], - easeOutQuad: [0.25, 0.46, 0.45, 0.94], - easeInOutQuad: [0.455, 0.03, 0.515, 0.955], - easeInCubic: [0.55, 0.055, 0.675, 0.19], - easeOutCubic: [0.215, 0.61, 0.355, 1], - easeInOutCubic: [0.645, 0.045, 0.355, 1], - easeInQuart: [0.895, 0.03, 0.685, 0.22], - easeOutQuart: [0.165, 0.84, 0.44, 1], - easeInOutQuart: [0.77, 0, 0.175, 1], - easeInQuint: [0.755, 0.05, 0.855, 0.06], - easeOutQuint: [0.23, 1, 0.32, 1], - easeInOutQuint: [0.86, 0, 0.07, 1], - easeInExpo: [0.95, 0.05, 0.795, 0.035], - easeOutExpo: [0.19, 1, 0.22, 1], - easeInOutExpo: [1, 0, 0, 1], - easeInCirc: [0.6, 0.04, 0.98, 0.335], - easeOutCirc: [0.075, 0.82, 0.165, 1], - easeInOutCirc: [0.785, 0.135, 0.15, 0.86], - easeInBack: [0.6, -0.28, 0.735, 0.045], - easeOutBack: [0.175, 0.885, 0.32, 1.275], - easeInOutBack: [0.68, -0.55, 0.265, 1.55] - }; - - Chartist.Svg.Easing = easingCubicBeziers; - - /** - * 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. - * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. - * - * @memberof Chartist.Svg - * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) - * @constructor - */ - function SvgList(nodeList) { - var list = this; - - this.svgElements = []; - for(var i = 0; i < nodeList.length; i++) { - this.svgElements.push(new Chartist.Svg(nodeList[i])); - } - - // Add delegation methods for Chartist.Svg - Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { - return ['constructor', - 'parent', - 'querySelector', - 'querySelectorAll', - 'replace', - 'append', - 'classes', - 'height', - 'width'].indexOf(prototypeProperty) === -1; - }).forEach(function(prototypeProperty) { - list[prototypeProperty] = function() { - var args = Array.prototype.slice.call(arguments, 0); - list.svgElements.forEach(function(element) { - Chartist.Svg.prototype[prototypeProperty].apply(element, args); - }); - return list; - }; - }); - } - - Chartist.Svg.List = Chartist.Class.extend({ - constructor: SvgList - }); - - }(window, document, Chartist)); - ;/** - * 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. - * - * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. - * - * @module Chartist.Line - */ - /* global Chartist */ - (function(window, document, Chartist){ - 'use strict'; - - var defaultOptions = { - axisX: { - offset: 30, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 40, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 20 - }, - width: undefined, - height: undefined, - showLine: true, - showPoint: true, - showArea: false, - areaBase: 0, - lineSmooth: true, - low: undefined, - high: undefined, - chartPadding: 5, - 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', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }; - - function createChart(options) { - var seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); - - // Create new svg object - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - - // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options); - - var chartRect = Chartist.createChartRect(this.svg, options); - // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup); - - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - - // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - seriesGroups[i] = this.svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var p, - pathCoordinates = [], - point; - - for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); - pathCoordinates.push(p.x, p.y); - - //If we should show points we need to create them now to avoid secondary loop - // Small offset for Firefox to render squares correctly - if (options.showPoint) { - point = seriesGroups[i].elem('line', { - x1: p.x, - y1: p.y, - x2: p.x + 0.01, - y2: p.y - }, options.classNames.point).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'point', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: point, - x: p.x, - y: p.y - }); - } - } - - // TODO: Nicer handling of conditions, maybe composition? - if (options.showLine || options.showArea) { - // TODO: We should add a path API in the SVG library for easier path creation - var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; - - // If smoothed path and path has more than two points then use catmull rom to bezier algorithm - if (options.lineSmooth && pathCoordinates.length > 4) { - - var cr = Chartist.catmullRom2bezier(pathCoordinates); - for(var k = 0; k < cr.length; k++) { - pathElements.push('C' + cr[k].join()); - } - } else { - for(var l = 3; l < pathCoordinates.length; l += 2) { - pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); - } - } - - if(options.showArea) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); - - // If we need to draw area shapes we just make a copy of our pathElements SVG path array - var areaPathElements = pathElements.slice(); - - // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); - // And splice our new area path array to add the missing path elements to close the area shape - areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); - areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; - areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); - - // Create the new path for the area shape with the area class from the options - var area = seriesGroups[i].elem('path', { - d: areaPathElements.join('') - }, options.classNames.area, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'area', - values: normalizedData[i], - index: i, - group: seriesGroups[i], - element: area - }); - } - - if(options.showLine) { - var line = seriesGroups[i].elem('path', { - d: pathElements.join('') - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[i], - index: i, - group: seriesGroups[i], - element: line - }); - } - } - } - - this.eventEmitter.emit('created', { - bounds: bounds, - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new line chart. - * - * @memberof Chartist.Line - * @param {String|Node} query A selector query string or directly a DOM element - * @param {Object} data The data object that needs to consist of a labels and a series array - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object which exposes the API for the created chart - * - * @example - * // These are the default options of the line chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the labels to the chart area - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the labels to the chart area - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // If the line should be drawn or not - * showLine: true, - * // If dots should be drawn or not - * showPoint: true, - * // If the line chart should draw an area - * showArea: false, - * // The base for the area chart that will be used to close the area shape (is normally 0) - * areaBase: 0, - * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) - * lineSmooth: true, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * 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', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example - * // Create a simple line chart - * var data = { - * // A labels array that can contain any sort of values - * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], - * // Our series array that contains series objects or in this case series data arrays - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // As options we currently only set a static size of 300x200 px - * var options = { - * width: '300px', - * height: '200px' - * }; - * - * // 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 - * new Chartist.Line('.ct-chart', data, options); - * - * @example - * // Create a line chart with responsive options - * - * var data = { - * // A labels array that can contain any sort of values - * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], - * // Our series array that contains series objects or in this case series data arrays - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. - * var responsiveOptions = [ - * ['screen and (min-width: 641px) and (max-width: 1024px)', { - * showPoint: false, - * axisX: { - * labelInterpolationFnc: function(value) { - * // Will return Mon, Tue, Wed etc. on medium screens - * return value.slice(0, 3); - * } - * } - * }], - * ['screen and (max-width: 640px)', { - * showLine: false, - * axisX: { - * labelInterpolationFnc: function(value) { - * // Will return M, T, W etc. on small screens - * return value[0]; - * } - * } - * }] - * ]; - * - * new Chartist.Line('.ct-chart', data, null, responsiveOptions); - * - */ - function Line(query, data, options, responsiveOptions) { - Chartist.Line.super.constructor.call(this, - query, - data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), - responsiveOptions); - } - - // Creating line chart type in Chartist namespace - Chartist.Line = Chartist.Base.extend({ - constructor: Line, - createChart: createChart - }); - - }(window, document, Chartist)); - ;/** - * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. - * - * @module Chartist.Bar - */ - /* global Chartist */ - (function(window, document, Chartist){ - 'use strict'; - - var defaultOptions = { - axisX: { - offset: 30, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop - }, - axisY: { - offset: 40, - labelOffset: { - x: 0, - y: 0 - }, - showLabel: true, - showGrid: true, - labelInterpolationFnc: Chartist.noop, - scaleMinSpace: 20 - }, - width: undefined, - height: undefined, - high: undefined, - low: undefined, - chartPadding: 5, - seriesBarDistance: 15, - classNames: { - chart: 'ct-chart-bar', - label: 'ct-label', - labelGroup: 'ct-labels', - series: 'ct-series', - bar: 'ct-bar', - grid: 'ct-grid', - gridGroup: 'ct-grids', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }; - - function createChart(options) { - var seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); - - // Create new svg element - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - - // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); - - var chartRect = Chartist.createChartRect(this.svg, options); - // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup), - // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); - - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - - // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = i - (this.data.series.length - 1) / 2, - // Half of the period with between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; - - seriesGroups[i] = this.svg.elem('g'); - - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), - bar; - - // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors - p.x += periodHalfWidth + (biPol * options.seriesBarDistance); - - bar = seriesGroups[i].elem('line', { - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }, options.classNames.bar).attr({ - 'value': normalizedData[i][j] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'bar', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: bar, - x1: p.x, - y1: zeroPoint.y, - x2: p.x, - y2: p.y - }); - } - } - - this.eventEmitter.emit('created', { - bounds: bounds, - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new bar chart and returns API object that you can use for later changes. - * - * @memberof Chartist.Bar - * @param {String|Node} query A selector query string or directly a DOM element - * @param {Object} data The data object that needs to consist of a labels and a series array - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object which exposes the API for the created chart - * - * @example - * // These are the default options of the bar chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the chart drawing area to the border of the container - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the chart drawing area to the border of the container - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Specify the distance in pixel of bars in a group - * seriesBarDistance: 15, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-bar', - * label: 'ct-label', - * labelGroup: 'ct-labels', - * series: 'ct-series', - * bar: 'ct-bar', - * grid: 'ct-grid', - * gridGroup: 'ct-grids', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example - * // Create a simple bar chart - * var data = { - * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // 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. - * new Chartist.Bar('.ct-chart', data); - * - * @example - * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 - * new Chartist.Bar('.ct-chart', { - * labels: [1, 2, 3, 4, 5, 6, 7], - * series: [ - * [1, 3, 2, -5, -3, 1, -6], - * [-5, -2, -4, -1, 2, -3, 1] - * ] - * }, { - * seriesBarDistance: 12, - * low: -10, - * high: 10 - * }); - * - */ - function Bar(query, data, options, responsiveOptions) { - Chartist.Bar.super.constructor.call(this, - query, - data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), - responsiveOptions); - } - - // Creating bar chart type in Chartist namespace - Chartist.Bar = Chartist.Base.extend({ - constructor: Bar, - createChart: createChart - }); - - }(window, document, Chartist)); - ;/** - * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts - * - * @module Chartist.Pie - */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - var defaultOptions = { - width: undefined, - height: undefined, - chartPadding: 5, - classNames: { - chart: 'ct-chart-pie', - series: 'ct-series', - slice: 'ct-slice', - donut: 'ct-donut', - label: 'ct-label' - }, - startAngle: 0, - total: undefined, - donut: false, - donutWidth: 60, - showLabel: true, - labelOffset: 0, - labelInterpolationFnc: Chartist.noop, - labelOverflow: false, - labelDirection: 'neutral' - }; - - function determineAnchorPosition(center, label, direction) { - var toTheRight = label.x > center.x; - - if(toTheRight && direction === 'explode' || - !toTheRight && direction === 'implode') { - return 'start'; - } else if(toTheRight && direction === 'implode' || - !toTheRight && direction === 'explode') { - return 'end'; - } else { - return 'middle'; - } - } - - function createChart(options) { - var seriesGroups = [], - chartRect, - radius, - labelRadius, - totalDataSum, - startAngle = options.startAngle, - dataArray = Chartist.getDataArray(this.data); - - // Create SVG.js draw - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - // Calculate charting rect - chartRect = Chartist.createChartRect(this.svg, options, 0, 0); - // Get biggest circle radius possible within chartRect - radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); - // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { - return previousValue + currentValue; - }, 0); - - // 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 ? options.donutWidth / 2 : 0; - - // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius - // see https://github.com/gionkunz/chartist-js/issues/21 - labelRadius = options.donut ? radius : radius / 2; - // Add the offset to the labelRadius where a negative offset means closed to the center of the chart - labelRadius += options.labelOffset; - - // Calculate end angle based on total sum and current data value and offset with padding - var center = { - x: chartRect.x1 + chartRect.width() / 2, - y: chartRect.y2 + chartRect.height() / 2 - }; - - // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = this.data.series.filter(function(val) { - return val !== 0; - }).length === 1; - - // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - seriesGroups[i] = this.svg.elem('g', null, null, true); - - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } - - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var endAngle = startAngle + dataArray[i] / totalDataSum * 360; - // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle - // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; - } - - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), - end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), - arcSweep = endAngle - startAngle <= 180 ? '0' : '1', - d = [ - // Start at the end point from the cartesian coordinates - 'M', end.x, end.y, - // Draw arc - 'A', radius, radius, 0, arcSweep, 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 === false) { - d.push('L', center.x, center.y); - } - - // Create the SVG path - // If this is a donut chart we add the donut class, otherwise just a regular slice - var path = seriesGroups[i].elem('path', { - d: d.join(' ') - }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); - - // Adding the pie series value to the path - path.attr({ - 'value': dataArray[i] - }, Chartist.xmlNs.uri); - - // If this is a donut, we add the stroke-width as style attribute - if(options.donut === true) { - path.attr({ - 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' - }); - } - - // Fire off draw event - this.eventEmitter.emit('draw', { - type: 'slice', - value: dataArray[i], - totalDataSum: totalDataSum, - index: i, - group: seriesGroups[i], - element: path, - center: center, - radius: radius, - startAngle: startAngle, - endAngle: endAngle - }); - - // If we need to show labels we need to add the label for this slice now - if(options.showLabel) { - // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); - - var labelElement = seriesGroups[i].elem('text', { - dx: labelPosition.x, - dy: labelPosition.y, - 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) - }, options.classNames.label).text('' + interpolatedValue); - - // Fire off draw event - this.eventEmitter.emit('draw', { - type: 'label', - index: i, - group: seriesGroups[i], - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y - }); - } - - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues - // (except for last slice) - startAngle = endAngle; - } - - this.eventEmitter.emit('created', { - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new pie chart and returns an object that can be used to redraw the chart. - * - * @memberof Chartist.Pie - * @param {String|Node} query A selector query string or directly a DOM element - * @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. - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object with a version and an update method to manually redraw the chart - * - * @example - * // Default options of the pie chart - * var defaultOptions = { - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-pie', - * series: 'ct-series', - * slice: 'ct-slice', - * donut: 'ct-donut', - label: 'ct-label' - * }, - * // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. - * startAngle: 0, - * // 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. - * total: undefined, - * // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. - * donut: false, - * // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. - * donutWidth: 60, - * // If a label should be shown or not - * showLabel: true, - * // 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. - * labelOffset: 0, - * // An interpolation function for the label value - * labelInterpolationFnc: function(value, index) {return value;}, - * // 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. - * labelDirection: 'neutral' - * }; - * - * @example - * // Simple pie chart example with four series - * new Chartist.Pie('.ct-chart', { - * series: [10, 2, 4, 3] - * }); - * - * @example - * // Drawing a donut chart - * new Chartist.Pie('.ct-chart', { - * series: [10, 2, 4, 3] - * }, { - * donut: true - * }); - * - * @example - * // Using donut, startAngle and total to draw a gauge chart - * new Chartist.Pie('.ct-chart', { - * series: [20, 10, 30, 40] - * }, { - * donut: true, - * donutWidth: 20, - * startAngle: 270, - * total: 200 - * }); - * - * @example - * // Drawing a pie chart with padding and labels that are outside the pie - * new Chartist.Pie('.ct-chart', { - * series: [20, 10, 30, 40] - * }, { - * chartPadding: 30, - * labelOffset: 50, - * labelDirection: 'explode' - * }); - */ - function Pie(query, data, options, responsiveOptions) { - Chartist.Pie.super.constructor.call(this, - query, - data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), - responsiveOptions); - } - - // Creating pie chart type in Chartist namespace - Chartist.Pie = Chartist.Base.extend({ - constructor: Pie, - createChart: createChart, - determineAnchorPosition: determineAnchorPosition - }); - - }(window, document, Chartist)); return Chartist; diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 06403e61..ce9aff64 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -4,5 +4,5 @@ * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a,b){a=a||{};for(var d in b)a[d]="object"==typeof b[d]?c.extend(a[d],b[d]):b[d];return a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e,f){function g(){var b=i;if(i=c.extend({},k),e)for(j=0;j0?e:null}var d={added:0,removed:0,modified:0},e=c(a,b);return e&&(e.__delta__.summary=d),e},c.catmullRom2bezier=function(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend(c.extend({},g),d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){return Chartist}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index ab2ba278..4171ed6d 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","forEach","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18979,"pos":18974,"col":16,"line":498,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":18979,"pos":18974,"col":16,"line":498,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","defaultOptions","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","deltaDescriptor","a","b","findDeltasRecursively","descriptor","__delta__","Object","keys","property","hasOwnProperty","subDescriptor","ours","theirs","summary","modified","removed","added","delta","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","prototype","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","apply","Array","slice","call","arguments","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":";;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,UAAW,WACT,MAAQF,GAAKI,oBAAsBH,MAET,gBAAZI,SAIhBC,OAAOD,QAAUJ,IAEjBD,EAAe,SAAIC,KAErBM,KAAM,WAYN,GAAIC,IACFC,QAAS,QAimFX,OA9lFC,UAAUC,EAAQC,EAAUH,GAC3B,YASAA,GAASI,KAAO,SAAUC,GACxB,MAAOA,IAUTL,EAASM,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAYtCL,EAASS,OAAS,SAAUC,EAAQC,GAClCD,EAASA,KACT,KAAK,GAAIE,KAAQD,GAEbD,EAAOE,GADmB,gBAAjBD,GAAOC,GACDZ,EAASS,OAAOC,EAAOE,GAAOD,EAAOC,IAErCD,EAAOC,EAG1B,OAAOF,IAUTV,EAASa,UAAY,SAASC,GAK5B,MAJoB,gBAAVA,KACRA,EAAQA,EAAMC,QAAQ,eAAgB,MAGhCD,GAWVd,EAASgB,WAAa,SAASF,EAAOG,GAKpC,MAJoB,gBAAVH,KACRA,GAAgBG,GAGXH,GAUTd,EAASkB,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQhB,EAASe,cAAcC,IAahEnB,EAASqB,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIC,EAqBJ,OAnBAH,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAEnBE,EAAMJ,EAAUJ,cAAc,OAC3BQ,GACDJ,EAAUK,YAAYD,GAIxBA,EAAM,GAAI1B,GAAS4B,IAAI,OAAOC,MAC5BN,MAAOA,EACPC,OAAQA,IACPM,SAASL,GAAWI,MACrBE,MAAO,UAAYR,EAAQ,aAAeC,EAAS,MAIrDF,EAAUU,YAAYN,EAAIO,OAEnBP,GAUT1B,EAASkC,aAAe,SAAUC,GAGhC,IAAK,GAFDC,MAEKC,EAAI,EAAGA,EAAIF,EAAKG,OAAOC,OAAQF,IAAK,CAG3CD,EAAMC,GAAgC,gBAApBF,GAAKG,OAAOD,IAA4CG,SAAxBL,EAAKG,OAAOD,GAAGF,KAC/DA,EAAKG,OAAOD,GAAGF,KAAOA,EAAKG,OAAOD,EAGpC,KAAK,GAAII,GAAI,EAAGA,EAAIL,EAAMC,GAAGE,OAAQE,IACnCL,EAAMC,GAAGI,IAAML,EAAMC,GAAGI,GAI5B,MAAOL,IAWTpC,EAAS0C,mBAAqB,SAAUC,EAAWJ,GACjD,IAAK,GAAIF,GAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IACpC,GAAIM,EAAUN,GAAGE,SAAWA,EAI5B,IAAK,GAAIE,GAAIE,EAAUN,GAAGE,OAAYA,EAAJE,EAAYA,IAC5CE,EAAUN,GAAGI,GAAK,CAItB,OAAOE,IAUT3C,EAAS4C,iBAAmB,SAAU9B,GACpC,MAAO+B,MAAKC,MAAMD,KAAKE,IAAIF,KAAKG,IAAIlC,IAAU+B,KAAKI,OAarDjD,EAASkD,cAAgB,SAAUxB,EAAKa,EAAQY,EAAQC,GACtD,GAAIC,GAAkBrD,EAASsD,mBAAmB5B,EAAK0B,EACvD,OAAQb,GAASY,EAAOI,MAAQF,GAWlCrD,EAASsD,mBAAqB,SAAU5B,EAAK0B,GAC3C,MAAOP,MAAKW,KAAKxD,EAASa,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAoC,EAAvB4B,EAAQK,aAAoBL,EAAQM,MAAMC,OAAQ,IAU5H3D,EAAS4D,WAAa,SAAUjB,GAC9B,GAAIN,GACFI,EACAoB,GACEC,MAAOC,OAAOC,UACdC,IAAKF,OAAOC,UAGhB,KAAK3B,EAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IAChC,IAAKI,EAAI,EAAGA,EAAIE,EAAUN,GAAGE,OAAQE,IAC/BE,EAAUN,GAAGI,GAAKoB,EAAQC,OAC5BD,EAAQC,KAAOnB,EAAUN,GAAGI,IAG1BE,EAAUN,GAAGI,GAAKoB,EAAQI,MAC5BJ,EAAQI,IAAMtB,EAAUN,GAAGI,GAKjC,OAAOoB,IAcT7D,EAASkE,UAAY,SAAUxC,EAAKyC,EAAgBf,EAASgB,GAC3D,GAAI/B,GACFgC,EACAC,EACAnB,EAASnD,EAAS4D,WAAWO,EAG/BhB,GAAOW,MAAQV,EAAQU,OAA0B,IAAjBV,EAAQU,KAAa,EAAIX,EAAOW,MAChEX,EAAOc,KAAOb,EAAQa,MAAwB,IAAhBb,EAAQa,IAAY,EAAId,EAAOc,KAI1Dd,EAAOW,OAASX,EAAOc,MAEN,IAAfd,EAAOc,IACRd,EAAOW,KAAO,EACNX,EAAOc,IAAM,EAErBd,EAAOW,KAAO,EAGdX,EAAOc,IAAM,IAObG,GAAqC,IAAnBA,KACpBjB,EAAOW,KAAOjB,KAAKW,IAAIY,EAAgBjB,EAAOW,MAC9CX,EAAOc,IAAMpB,KAAK0B,IAAIH,EAAgBjB,EAAOc,MAG/Cd,EAAOqB,WAAarB,EAAOW,KAAOX,EAAOc,IACzCd,EAAOsB,IAAMzE,EAAS4C,iBAAiBO,EAAOqB,YAC9CrB,EAAOoB,IAAM1B,KAAKC,MAAMK,EAAOc,IAAMpB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOK,IAAMX,KAAK8B,KAAKxB,EAAOW,KAAOjB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IACnCpB,EAAOyB,KAAO/B,KAAK6B,IAAI,GAAIvB,EAAOsB,KAClCtB,EAAO0B,cAAgBhC,KAAKiC,MAAM3B,EAAOI,MAAQJ,EAAOyB,KAOxD,KAHA,GAAIrC,GAASvC,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,GAC5D2B,EAAUxC,EAASa,EAAQ4B,MAAMC,gBAGjC,GAAIF,GAAW/E,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,IAAYA,EAAQ4B,MAAMC,cACxF9B,EAAOyB,MAAQ,MACV,CAAA,GAAKG,KAAW/E,EAASkD,cAAcxB,EAAKyB,EAAOyB,KAAO,EAAGzB,EAAQC,IAAYA,EAAQ4B,MAAMC,eAGpG,KAFA9B,GAAOyB,MAAQ,EASnB,IAFAP,EAASlB,EAAOoB,IAChBD,EAASnB,EAAOK,IACXnB,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAC5CvC,EAAIc,EAAOyB,KAAOzB,EAAOc,MAC3BI,GAAUlB,EAAOyB,MAGfvC,EAAIc,EAAOyB,MAAQzB,EAAOW,OAC5BQ,GAAUnB,EAAOyB,KAQrB,KALAzB,EAAOoB,IAAMF,EACblB,EAAOK,IAAMc,EACbnB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IAEnCpB,EAAO+B,UACF7C,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAChDzB,EAAO+B,OAAOC,KAAK9C,EAGrB,OAAOc,IAaTnD,EAASoF,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAM3C,KAAK6C,GAAK,GAEvD,QACEC,EAAGN,EAAWE,EAAS1C,KAAK+C,IAAIH,GAChCI,EAAGP,EAAWC,EAAS1C,KAAKiD,IAAIL,KAYpCzF,EAAS+F,gBAAkB,SAAUrE,EAAK0B,GACxC,GAAI4C,GAAU5C,EAAQ4B,MAAQ5B,EAAQ4B,MAAMrB,OAAS,EACnDsC,EAAU7C,EAAQM,MAAQN,EAAQM,MAAMC,OAAS,CAEnD,QACEuC,GAAI9C,EAAQK,aAAeuC,EAC3BG,GAAItD,KAAKW,KAAKxD,EAASa,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAY4B,EAAQK,aAAewC,EAAS7C,EAAQK,cAC5G2C,GAAIvD,KAAKW,KAAKxD,EAASa,UAAUuC,EAAQ7B,QAAUG,EAAIH,SAAW6B,EAAQK,aAAcL,EAAQK,aAAeuC,GAC/GK,GAAIjD,EAAQK,aACZlC,MAAO,WACL,MAAOxB,MAAKqG,GAAKrG,KAAKmG,IAExB1E,OAAQ,WACN,MAAOzB,MAAKoG,GAAKpG,KAAKsG,MAe5BrG,EAASsG,YAAc,SAASC,EAAQC,EAAMC,EAAYhF,EAAWiF,GACnE,GAAGA,EAAuB,CACxB,GAAIC,GAAU,gBAAkBlF,EAAY,KAAO+E,EAAO,SAC1D,OAAOD,GAAOK,cAAcD,EAASF,GAErC,MAAOF,GAAOM,KAAK,OAAQJ,EAAYhF,GAAW+E,KAAKA,IAgB3DxG,EAAS8G,YAAc,SAAUC,EAAW5E,EAAM6E,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAErFvE,EAAK8E,OAAOE,QAAQ,SAAUrG,EAAOsG,GACnC,GAAIC,GAAoBjE,EAAQM,MAAM4D,sBAAsBxG,EAAOsG,GACjE7F,EAAQwF,EAAUxF,QAAUY,EAAK8E,OAAO1E,OACxCf,EAAS4B,EAAQM,MAAMC,OACvB4D,EAAMR,EAAUb,GAAK3E,EAAQ6F,CAG/B,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIjE,EAAQM,MAAM8D,SAAU,CAC1B,GAAIC,GAAcT,EAAKH,KAAK,QAC1BX,GAAIqB,EACJpB,GAAIY,EAAUZ,GACdC,GAAImB,EACJlB,GAAIU,EAAUV,KACZjD,EAAQsE,WAAWV,KAAM5D,EAAQsE,WAAWC,YAAYC,KAAK,KAGjEV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTvB,GAAIqB,EACJpB,GAAIY,EAAUZ,GACdC,GAAImB,EACJlB,GAAIU,EAAUV,KAIlB,GAAIjD,EAAQM,MAAMwE,UAAW,CAC3B,GAAIC,IACFxC,EAAG4B,EAAMnE,EAAQM,MAAM0E,YAAYzC,EACnCE,EAAGkB,EAAUZ,GAAK/C,EAAQM,MAAM0E,YAAYvC,GAAKa,EAAwB,EAAI,KAG3E2B,EAAerI,EAASsG,YAAYW,EAAQ,GAAKI,GACnD1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQsE,WAAWY,MAAOlF,EAAQsE,WAAWC,YAAYC,KAAK,KAAMlB,EAExEQ,GAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EAER+G,GAAIC,SAEF,MADAtI,GAAOuI,QAAQC,KAAK,mEACb3I,KAAKwB,cAmBtBvB,EAAS2I,YAAc,SAAU5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAEvFvD,EAAO+B,OAAOiC,QAAQ,SAAUrG,EAAOsG,GACrC,GAAIC,GAAoBjE,EAAQ4B,MAAMsC,sBAAsBxG,EAAOsG,GACjE7F,EAAQ6B,EAAQ4B,MAAMrB,OACtBnC,EAASuF,EAAUvF,SAAW2B,EAAO+B,OAAO3C,OAC5CgF,EAAMR,EAAUZ,GAAK3E,EAAS4F,CAGhC,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIjE,EAAQ4B,MAAMwC,SAAU,CAC1B,GAAIC,GAAcT,EAAKH,KAAK,QAC1BX,GAAIa,EAAUb,GACdC,GAAIoB,EACJnB,GAAIW,EAAUX,GACdC,GAAIkB,IACFnE,EAAQsE,WAAWV,KAAM5D,EAAQsE,WAAWkB,UAAUhB,KAAK,KAG/DV,GAAaW,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOhB,EACPiB,QAASR,EACTvB,GAAIa,EAAUb,GACdC,GAAIoB,EACJnB,GAAIW,EAAUX,GACdC,GAAIkB,IAIR,GAAInE,EAAQ4B,MAAMkD,UAAW,CAC3B,GAAIC,IACFxC,EAAGvC,EAAQK,aAAeL,EAAQ4B,MAAMoD,YAAYzC,GAAKe,EAAwB,IAAM,GACvFb,EAAG0B,EAAMnE,EAAQ4B,MAAMoD,YAAYvC,GAAKa,EAAwB,IAAM,IAGpE2B,EAAerI,EAASsG,YAAYW,EAAQ,GAAKI,GACnD1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQsE,WAAWY,MAAOlF,EAAQsE,WAAWkB,UAAUhB,KAAK,KAAMlB,EAEtEQ,GAAaW,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,EACjBtE,MAAOA,EACPC,OAAQA,EAER+G,GAAIC,SAEF,MADAtI,GAAOuI,QAAQC,KAAK,mEACb3I,KAAKyB,eAiBtBxB,EAAS6I,aAAe,SAAU9B,EAAW5D,EAAQhB,EAAMiF,GACzD,OACEzB,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAUY,EAAKI,OAAS6E,EACpDvB,EAAGkB,EAAUZ,GAAKY,EAAUvF,UAAYW,EAAKiF,GAASjE,EAAOoB,MAAQpB,EAAOI,MAAQJ,EAAOyB,QAe/F5E,EAAS8I,gBAAkB,SAAUC,EAAgB3F,EAAS4F,EAAmB9B,GAM/E,QAAS+B,KACP,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiBnJ,EAASS,UAAW2I,GAEjCJ,EACF,IAAK3G,EAAI,EAAGA,EAAI2G,EAAkBzG,OAAQF,IAAK,CAC7C,GAAIgH,GAAMnJ,EAAOoJ,WAAWN,EAAkB3G,GAAG,GAC7CgH,GAAIE,UACNJ,EAAiBnJ,EAASS,OAAO0I,EAAgBH,EAAkB3G,GAAG,KAKzE6E,GACDA,EAAaW,KAAK,kBAChBqB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoBtC,QAAQ,SAASkC,GACnCA,EAAIK,eAAeT,KA5BvB,GACEE,GAEA9G,EAHE+G,EAAcpJ,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GAErEqG,IA8BF,KAAKvJ,EAAOoJ,WACV,KAAM,iEACD,IAAIN,EAET,IAAK3G,EAAI,EAAGA,EAAI2G,EAAkBzG,OAAQF,IAAK,CAC7C,GAAIgH,GAAMnJ,EAAOoJ,WAAWN,EAAkB3G,GAAG,GACjDgH,GAAIM,YAAYV,GAChBQ,EAAoBtE,KAAKkE,GAM7B,MAFAJ,MAGEV,GAAIY,kBACF,MAAOnJ,GAASS,UAAW0I,IAE7BK,0BAA2BA,IAe/BxJ,EAAS4J,gBAAkB,SAASC,EAAGC,GAOrC,QAASC,GAAsBF,EAAGC,GAChC,GAAIE,IACFC,aA4CF,OAxCAC,QAAOC,KAAKN,GAAG1C,QAAQ,SAASiD,GAC9B,GAAIN,EAAEO,eAAeD,GAQnB,GAA0B,gBAAhBP,GAAEO,GAAwB,CAClC,GAAIE,GAAgBP,EAAsBF,EAAEO,GAAWN,EAAEM,GACtDE,KACDN,EAAWI,GAAYE,OAGtBT,GAAEO,KAAcN,EAAEM,KACnBJ,EAAWC,UAAUG,IACnBtC,KAAM,SACNsC,SAAUA,EACVG,KAAMV,EAAEO,GACRI,OAAQV,EAAEM,IAEZK,EAAQC,gBApBZV,GAAWC,UAAUG,IACnBtC,KAAM,SACNsC,SAAUA,EACVG,KAAMV,EAAEO,IAEVK,EAAQE,YAsBZT,OAAOC,KAAKL,GAAG3C,QAAQ,SAASiD,GAC1BP,EAAEQ,eAAeD,KACnBJ,EAAWC,UAAUG,IACnBtC,KAAM,QACNsC,SAAUA,EACVI,OAAQV,EAAEM,IAEZK,EAAQG,WAI+B,IAAnCV,OAAOC,KAAKH,GAAYzH,QAAgB2H,OAAOC,KAAKH,EAAWC,WAAW1H,OAAS,EAAKyH,EAAa,KApD/G,GAAIS,IACFG,MAAO,EACPD,QAAS,EACTD,SAAU,GAoDRG,EAAQd,EAAsBF,EAAGC,EAKrC,OAJGe,KACDA,EAAMZ,UAAUQ,QAAUA,GAGrBI,GAIT7K,EAAS8K,kBAAoB,SAAUC,EAAKC,GAE1C,IAAK,GADDC,MACK5I,EAAI,EAAG6I,EAAOH,EAAIxI,OAAQ2I,EAAO,GAAKF,EAAI3I,EAAGA,GAAK,EAAG,CAC5D,GAAI8I,KACDxF,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,KAC5BsD,GAAIoF,EAAI1I,GAAIwD,GAAIkF,EAAI1I,EAAI,KACxBsD,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,KAC5BsD,GAAIoF,EAAI1I,EAAI,GAAIwD,GAAIkF,EAAI1I,EAAI,IAE3B2I,GACG3I,EAEM6I,EAAO,IAAM7I,EACtB8I,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,IACnBG,EAAO,IAAM7I,IACtB8I,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,IAC5BI,EAAE,IAAMxF,GAAIoF,EAAI,GAAIlF,GAAIkF,EAAI,KAL5BI,EAAE,IAAMxF,GAAIoF,EAAIG,EAAO,GAAIrF,GAAIkF,EAAIG,EAAO,IAQxCA,EAAO,IAAM7I,EACf8I,EAAE,GAAKA,EAAE,GACC9I,IACV8I,EAAE,IAAMxF,GAAIoF,EAAI1I,GAAIwD,GAAIkF,EAAI1I,EAAI,KAGpC4I,EAAE9F,QAEIgG,EAAE,GAAGxF,EAAI,EAAIwF,EAAE,GAAGxF,EAAIwF,EAAE,GAAGxF,GAAK,IAChCwF,EAAE,GAAGtF,EAAI,EAAIsF,EAAE,GAAGtF,EAAIsF,EAAE,GAAGtF,GAAK,GACjCsF,EAAE,GAAGxF,EAAI,EAAIwF,EAAE,GAAGxF,EAAIwF,EAAE,GAAGxF,GAAK,GAChCwF,EAAE,GAAGtF,EAAI,EAAIsF,EAAE,GAAGtF,EAAIsF,EAAE,GAAGtF,GAAK,EACjCsF,EAAE,GAAGxF,EACLwF,EAAE,GAAGtF,IAKX,MAAOoF,KAGT/K,OAAQC,SAAUH,GAOnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAASoL,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAOnG,KAAKoG,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAO/I,cACViJ,GAASF,UAIXE,GAASF,IAYtB,QAASzD,GAAKyD,EAAOnJ,GAEhBqJ,EAASF,IACVE,EAASF,GAAOnE,QAAQ,SAASoE,GAC/BA,EAAQpJ,KAKTqJ,EAAS,MACVA,EAAS,KAAKrE,QAAQ,SAASyE,GAC7BA,EAAYN,EAAOnJ,KAvDzB,GAAIqJ,KA4DJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpB5D,KAAMA,KAIV3H,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAAS6L,GAAYC,GACnB,GAAIC,KACJ,IAAID,EAAKvJ,OACP,IAAK,GAAIF,GAAI,EAAGA,EAAIyJ,EAAKvJ,OAAQF,IAC/B0J,EAAI5G,KAAK2G,EAAKzJ,GAGlB,OAAO0J,GA4CT,QAAStL,GAAOuL,EAAYC,GAC1B,GAAIC,GAAaD,GAAsBlM,KAAKoM,WAAanM,EAASoM,MAC9DC,EAAQnC,OAAOoC,OAAOJ,EAE1BlM,GAASoM,MAAMG,iBAAiBF,EAAOL,EAEvC,IAAIQ,GAAS,WACX,GACEC,GADEC,EAAKL,EAAMM,aAAe,YAU9B,OALAF,GAAW1M,OAASC,EAAWkK,OAAOoC,OAAOD,GAAStM,KACtD2M,EAAGE,MAAMH,EAAUI,MAAMV,UAAUW,MAAMC,KAAKC,UAAW,IAIlDP,EAOT,OAJAD,GAAOL,UAAYE,EACnBG,EAAOS,MAAQf,EACfM,EAAO/L,OAASV,KAAKU,OAEd+L,EA0FT,QAASU,GAAIC,EAAanB,GACxB,GAAGjM,OAASC,EAASoM,MACnB,KAAM,IAAIgB,OAAM,iFAIlB,IAAIC,QACDC,OAAOH,GACPI,IAAI,SAAUpB,GACb,MAAOA,aAAqBqB,UAAWrB,EAAUA,UAAYA,IAG7DsB,EAAkBzN,EAASoM,MAAMG,iBAAiBK,MAAMpK,OAAW6K,EAGvE,cADOI,GAAgBd,YAChB5M,KAAKU,OAAOuL,EAAYyB,GAIjC,QAASlB,KACP,GAAImB,GAAO7B,EAAYmB,WACnBtM,EAASgN,EAAK,EAYlB,OAVAA,GAAKhC,OAAO,EAAGgC,EAAKnL,OAAS,GAAG4E,QAAQ,SAAUxG,GAChDuJ,OAAOyD,oBAAoBhN,GAAQwG,QAAQ,SAAUyG,SAE5ClN,GAAOkN,GAEd1D,OAAO2D,eAAenN,EAAQkN,EAC5B1D,OAAO4D,yBAAyBnN,EAAQiN,QAIvClN,EAGTV,EAASoM,OACP3L,OAAQA,EACRyM,IAAKA,EACLX,iBAAkBA,IAGpBrM,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAaA,SAAS+N,KAEP,MADAhO,MAAKiO,YAAYjO,KAAK+I,gBAAgBK,gBAC/BpJ,KAQT,QAASkO,KAGP,MAFA/N,GAAOgO,oBAAoB,SAAUnO,KAAKoO,gBAC1CpO,KAAK+I,gBAAgBU,4BACdzJ,KAUT,QAASqO,GAAG9C,EAAOC,GAEjB,MADAxL,MAAKmH,aAAamE,gBAAgBC,EAAOC,GAClCxL,KAUT,QAASsO,GAAI/C,EAAOC,GAElB,MADAxL,MAAKmH,aAAauE,mBAAmBH,EAAOC,GACrCxL,KAYT,QAASuO,GAAKnN,EAAOgB,EAAMiB,EAAS4F,GAClCjJ,KAAKuB,UAAYtB,EAASkB,cAAcC,GACxCpB,KAAKoC,KAAOA,EACZpC,KAAKqD,QAAUA,EACfrD,KAAKiJ,kBAAoBA,EACzBjJ,KAAKmH,aAAelH,EAASoL,eAC7BrL,KAAK2G,sBAAwB1G,EAAS4B,IAAI2M,YAAY,iBACtDxO,KAAKyO,mBAAqBxO,EAAS4B,IAAI2M,YAAY,4BACnDxO,KAAKoO,eAAiB,WACpBpO,KAAKgO,UACLU,KAAK1O,MAEJA,KAAKuB,YAEHvB,KAAKuB,UAAUoN,cAChB3O,KAAKuB,UAAUoN,aAAaT,SAG9BlO,KAAKuB,UAAUoN,aAAe3O,MAGhCG,EAAOyO,iBAAiB,SAAU5O,KAAKoO,gBAIvCS,WAAW,WAIT7O,KAAK+I,gBAAkB9I,EAAS8I,mBAAoB/I,KAAKqD,QAASrD,KAAKiJ,kBAAmBjJ,KAAKmH,cAC/FnH,KAAKiO,YAAYjO,KAAK+I,gBAAgBK,iBACtCsF,KAAK1O,MAAO,GAIhBC,EAASsO,KAAOtO,EAASoM,MAAM3L,QAC7BkM,YAAa2B,EACbxF,gBAAiBtG,OACjBlB,UAAWkB,OACXd,IAAKc,OACL0E,aAAc1E,OACdwL,YAAa,WACX,KAAM,IAAIZ,OAAM,2CAElBW,OAAQA,EACRE,OAAQA,EACRG,GAAIA,EACJC,IAAKA,EACLpO,QAASD,EAASC,QAClByG,uBAAuB,KAGzBxG,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAuBA,SAAS4B,GAAIiN,EAAMpI,EAAYhF,EAAW8E,EAAQuI,GAE7CD,YAAgBE,YACjBhP,KAAKkC,MAAQ4M,GAEb9O,KAAKkC,MAAQ9B,EAAS6O,gBAAgBC,EAAOJ,GAGjC,QAATA,GACD9O,KAAKkC,MAAMiN,eAAeC,EAAOnP,EAASmP,MAAMC,cAAepP,EAASmP,MAAME,KAG7E5I,GACD1G,KAAK8B,KAAK4E,GAGThF,GACD1B,KAAK+B,SAASL,GAGb8E,IACGuI,GAAevI,EAAOtE,MAAMqN,WAC9B/I,EAAOtE,MAAMsN,aAAaxP,KAAKkC,MAAOsE,EAAOtE,MAAMqN,YAEnD/I,EAAOtE,MAAMD,YAAYjC,KAAKkC,SActC,QAASJ,GAAK4E,EAAY+I,GACxB,MAAyB,gBAAf/I,GACL+I,EACMzP,KAAKkC,MAAMwN,eAAeD,EAAI/I,GAE9B1G,KAAKkC,MAAMyN,aAAajJ,IAInCyD,OAAOC,KAAK1D,GAAYU,QAAQ,SAASwI,GAEhBnN,SAApBiE,EAAWkJ,KAIXH,EACDzP,KAAKkC,MAAMiN,eAAeM,GAAKxP,EAASmP,MAAMS,OAAQ,IAAKD,GAAK/H,KAAK,IAAKnB,EAAWkJ,IAErF5P,KAAKkC,MAAM4N,aAAaF,EAAKlJ,EAAWkJ,MAE1ClB,KAAK1O,OAEAA,MAaT,QAAS8G,GAAKgI,EAAMpI,EAAYhF,EAAWqN,GACzC,MAAO,IAAI9O,GAAS4B,IAAIiN,EAAMpI,EAAYhF,EAAW1B,KAAM+O,GAQ7D,QAASvI,KACP,MAAOxG,MAAKkC,MAAM6N,qBAAsBf,YAAa,GAAI/O,GAAS4B,IAAI7B,KAAKkC,MAAM6N,YAAc,KAQjG,QAAStQ,KAEP,IADA,GAAIuQ,GAAOhQ,KAAKkC,MACQ,QAAlB8N,EAAKC,UACTD,EAAOA,EAAKD,UAEd,OAAO,IAAI9P,GAAS4B,IAAImO,GAS1B,QAAS7O,GAAc+O,GACrB,GAAIC,GAAYnQ,KAAKkC,MAAMf,cAAc+O,EACzC,OAAOC,GAAY,GAAIlQ,GAAS4B,IAAIsO,GAAa,KASnD,QAASC,GAAiBF,GACxB,GAAIG,GAAarQ,KAAKkC,MAAMkO,iBAAiBF,EAC7C,OAAOG,GAAW7N,OAAS,GAAIvC,GAAS4B,IAAIyO,KAAKD,GAAc,KAajE,QAASxJ,GAAcD,EAASF,EAAYhF,EAAWqN,GAGrD,GAAsB,gBAAZnI,GAAsB,CAC9B,GAAIrF,GAAYnB,EAASmQ,cAAc,MACvChP,GAAUiP,UAAY5J,EACtBA,EAAUrF,EAAUgO,WAItB3I,EAAQkJ,aAAa,QAASW,EAI9B,IAAIC,GAAQ1Q,KAAK8G,KAAK,gBAAiBJ,EAAYhF,EAAWqN,EAK9D,OAFA2B,GAAMxO,MAAMD,YAAY2E,GAEjB8J,EAUT,QAASjK,GAAKkK,GAEZ,MADA3Q,MAAKkC,MAAMD,YAAY7B,EAASwQ,eAAeD,IACxC3Q,KAST,QAAS6Q,KACP,KAAO7Q,KAAKkC,MAAMqN,YAChBvP,KAAKkC,MAAMN,YAAY5B,KAAKkC,MAAMqN,WAGpC,OAAOvP,MAST,QAAS8Q,KAEP,MADA9Q,MAAKkC,MAAM6N,WAAWnO,YAAY5B,KAAKkC,OAChC,GAAIjC,GAAS4B,IAAI7B,KAAKkC,MAAM6N,YAUrC,QAAS/O,GAAQ+P,GAEf,MADA/Q,MAAKkC,MAAM6N,WAAWiB,aAAaD,EAAW7O,MAAOlC,KAAKkC,OACnD6O,EAWT,QAASE,GAAO/I,EAAS6G,GAOvB,MANGA,IAAe/O,KAAKkC,MAAMqN,WAC3BvP,KAAKkC,MAAMsN,aAAatH,EAAQhG,MAAOlC,KAAKkC,MAAMqN,YAElDvP,KAAKkC,MAAMD,YAAYiG,EAAQhG,OAG1BlC,KAST,QAASkR,KACP,MAAOlR,MAAKkC,MAAMyN,aAAa,SAAW3P,KAAKkC,MAAMyN,aAAa,SAASwB,OAAOC,MAAM,UAU1F,QAASrP,GAASsP,GAShB,MARArR,MAAKkC,MAAM4N,aAAa,QACtB9P,KAAKkR,QAAQlR,KAAKkC,OACfqL,OAAO8D,EAAMF,OAAOC,MAAM,QAC1BE,OAAO,SAASxK,EAAMU,EAAK+J,GAC1B,MAAOA,GAAK3F,QAAQ9E,KAAUU,IAC7BK,KAAK,MAGL7H,KAUT,QAASwR,GAAYH,GACnB,GAAII,GAAiBJ,EAAMF,OAAOC,MAAM,MAMxC,OAJApR,MAAKkC,MAAM4N,aAAa,QAAS9P,KAAKkR,QAAQlR,KAAKkC,OAAOoP,OAAO,SAASxC,GACxE,MAAwC,KAAjC2C,EAAe7F,QAAQkD,KAC7BjH,KAAK,MAED7H,KAST,QAAS0R,KAGP,MAFA1R,MAAKkC,MAAM4N,aAAa,QAAS,IAE1B9P,KAUT,QAASyB,KACP,MAAOzB,MAAKkC,MAAMyP,cAAgB7O,KAAKiC,MAAM/E,KAAKkC,MAAM0P,UAAUnQ,SAAWzB,KAAKkC,MAAM6N,WAAW4B,aAUrG,QAASnQ,KACP,MAAOxB,MAAKkC,MAAM2P,aAAe/O,KAAKiC,MAAM/E,KAAKkC,MAAM0P,UAAUpQ,QAAUxB,KAAKkC,MAAM6N,WAAW8B,YA4CnG,QAASC,GAAQC,EAAYC,EAAQ7K,GAiGnC,MAhGc1E,UAAXuP,IACDA,GAAS,GAGX7H,OAAOC,KAAK2H,GAAY3K,QAAQ,SAAoC6K,GAElE,QAASC,GAAcC,EAAqBH,GAC1C,GACEF,GACAM,EACAC,EAHEC,IAODH,GAAoBE,SAErBA,EAASF,EAAoBE,iBAAkBvF,OAC7CqF,EAAoBE,OACpBpS,EAAS4B,IAAI0Q,OAAOJ,EAAoBE,cACnCF,GAAoBE,QAI7BF,EAAoBK,MAAQvS,EAASgB,WAAWkR,EAAoBK,MAAO,MAC3EL,EAAoBM,IAAMxS,EAASgB,WAAWkR,EAAoBM,IAAK,MAEpEJ,IACDF,EAAoBO,SAAW,SAC/BP,EAAoBQ,WAAaN,EAAOxK,KAAK,KAC7CsK,EAAoBS,SAAW,OAI9BZ,IACDG,EAAoBU,KAAO,SAE3BP,EAAoBL,GAAaE,EAAoBW,KACrD9S,KAAK8B,KAAKwQ,GAIVF,EAAUnS,EAASa,UAAUqR,EAAoBK,OAAS,GAC1DL,EAAoBK,MAAQ,cAG9BV,EAAU9R,KAAK8G,KAAK,UAAW7G,EAASS,QACtCqS,cAAed,GACdE,IAEAH,GAEDnD,WAAW,WACTiD,EAAQ5P,MAAM8Q,gBACbZ,GAGFjL,GACD2K,EAAQ5P,MAAM0M,iBAAiB,aAAc,WAC3CzH,EAAaW,KAAK,kBAChBI,QAASlI,KACT8R,QAASA,EAAQ5P,MACjB+Q,OAAQd,KAEVzD,KAAK1O,OAGT8R,EAAQ5P,MAAM0M,iBAAiB,WAAY,WACtCzH,GACDA,EAAaW,KAAK,gBAChBI,QAASlI,KACT8R,QAASA,EAAQ5P,MACjB+Q,OAAQd,IAITH,IAEDM,EAAoBL,GAAaE,EAAoBe,GACrDlT,KAAK8B,KAAKwQ,GAEVR,EAAQhB,WAEVpC,KAAK1O,OAIN+R,EAAWE,YAAsBnF,OAClCiF,EAAWE,GAAW7K,QAAQ,SAAS+K,GACrCD,EAAcxD,KAAK1O,MAAMmS,GAAqB,IAC9CzD,KAAK1O,OAEPkS,EAAcxD,KAAK1O,MAAM+R,EAAWE,GAAYD,IAGlDtD,KAAK1O,OAEAA,KA+ET,QAASmT,GAAQC,GACf,GAAIrH,GAAO/L,IAEXA,MAAKqT,cACL,KAAI,GAAI/Q,GAAI,EAAGA,EAAI8Q,EAAS5Q,OAAQF,IAClCtC,KAAKqT,YAAYjO,KAAK,GAAInF,GAAS4B,IAAIuR,EAAS9Q,IAIlD6H,QAAOC,KAAKnK,EAAS4B,IAAIuK,WAAWkF,OAAO,SAASgC,GAClD,MAQ4C,MARpC,cACJ,SACA,gBACA,mBACA,UACA,SACA,UACA,SACA,SAAS1H,QAAQ0H,KACpBlM,QAAQ,SAASkM,GAClBvH,EAAKuH,GAAqB,WACxB,GAAI3F,GAAOb,MAAMV,UAAUW,MAAMC,KAAKC,UAAW,EAIjD,OAHAlB,GAAKsH,YAAYjM,QAAQ,SAASc,GAChCjI,EAAS4B,IAAIuK,UAAUkH,GAAmBzG,MAAM3E,EAASyF,KAEpD5B,KAnjBb,GAAImD,GAAQ,6BACVE,EAAQ,gCACRqB,EAAU,8BAEZxQ,GAASmP,OACPC,cAAe,WACfQ,OAAQ,KACRP,IAAK,6CAucPrP,EAAS4B,IAAM5B,EAASoM,MAAM3L,QAC5BkM,YAAa/K,EACbC,KAAMA,EACNgF,KAAMA,EACNN,OAAQA,EACR/G,KAAMA,EACN0B,cAAeA,EACfiP,iBAAkBA,EAClBvJ,cAAeA,EACfJ,KAAMA,EACNoK,MAAOA,EACPC,OAAQA,EACR9P,QAASA,EACTiQ,OAAQA,EACRC,QAASA,EACTnP,SAAUA,EACVyP,YAAaA,EACbE,iBAAkBA,EAClBjQ,OAAQA,EACRD,MAAOA,EACPsQ,QAASA,IAUX7R,EAAS4B,IAAI2M,YAAc,SAAS+E,GAClC,MAAOnT,GAASoT,eAAeC,WAAW,sCAAwCF,EAAS,OAQ7F,IAAIG,IACFC,YAAa,IAAM,EAAG,KAAO,MAC7BC,aAAc,IAAM,KAAO,KAAO,GAClCC,eAAgB,KAAO,IAAM,IAAM,KACnCC,YAAa,IAAM,KAAO,IAAM,KAChCC,aAAc,IAAM,IAAM,IAAM,KAChCC,eAAgB,KAAO,IAAM,KAAO,MACpCC,aAAc,IAAM,KAAO,KAAO,KAClCC,cAAe,KAAO,IAAM,KAAO,GACnCC,gBAAiB,KAAO,KAAO,KAAO,GACtCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,KAAO,IAAM,IAAM,GAClCC,gBAAiB,IAAM,EAAG,KAAO,GACjCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,IAAM,EAAG,IAAM,GAC9BC,gBAAiB,IAAM,EAAG,IAAM,GAChCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,IAAM,EAAG,IAAM,GAC7BC,eAAgB,EAAG,EAAG,EAAG,GACzBC,YAAa,GAAK,IAAM,IAAM,MAC9BC,aAAc,KAAO,IAAM,KAAO,GAClCC,eAAgB,KAAO,KAAO,IAAM,KACpCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,KAAO,KAAO,IAAM,OAClCC,eAAgB,KAAO,IAAM,KAAO,MAGtCjV,GAAS4B,IAAI0Q,OAASmB,EAwCtBzT,EAAS4B,IAAIyO,KAAOrQ,EAASoM,MAAM3L,QACjCkM,YAAauG,KAGfhT,OAAQC,SAAUH,GASnB,SAASE,EAAQC,EAAUH,GAC1B,YAiDA,SAASgO,GAAY5K,GACnB,GACED,GADE+R,KAEF/Q,EAAiBnE,EAAS0C,mBAAmB1C,EAASkC,aAAanC,KAAKoC,MAAOpC,KAAKoC,KAAK8E,OAAO1E,OAGlGxC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAGhGhS,EAASnD,EAASkE,UAAUnE,KAAK2B,IAAKyC,EAAgBf,EAEtD,IAAI2D,GAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,GAE/C6D,EAASlH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW0N,YAC1DpO,EAAOjH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW2N,UAExDrV,GAAS8G,YAAYC,EAAWhH,KAAKoC,KAAM6E,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,uBAC1F1G,EAAS2I,YAAY5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAChD6S,EAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,KAG7B9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAMP,KAAK,GAJDuD,GAEFoK,EADAC,KAGO/S,EAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAC5C0I,EAAInL,EAAS6I,aAAa9B,EAAW5D,EAAQgB,EAAe9B,GAAII,GAChE+S,EAAgBrQ,KAAKgG,EAAExF,EAAGwF,EAAEtF,GAIxBzC,EAAQqS,YACVF,EAAQL,EAAa7S,GAAGwE,KAAK,QAC3BX,GAAIiF,EAAExF,EACNQ,GAAIgF,EAAEtF,EACNO,GAAI+E,EAAExF,EAAI,IACVU,GAAI8E,EAAEtF,GACLzC,EAAQsE,WAAW6N,OAAO1T,MAC3Bf,MAASqD,EAAe9B,GAAGI,IAC1BzC,EAASmP,MAAME,KAElBtP,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNhH,MAAOqD,EAAe9B,GAAGI,GACzB2E,MAAO3E,EACPuF,MAAOkN,EAAa7S,GACpB4F,QAASsN,EACT5P,EAAGwF,EAAExF,EACLE,EAAGsF,EAAEtF,IAMX,IAAIzC,EAAQsS,UAAYtS,EAAQuS,SAAU,CAExC,GAAIC,IAAgB,IAAMJ,EAAgB,GAAK,IAAMA,EAAgB,GAGrE,IAAIpS,EAAQyS,YAAcL,EAAgBjT,OAAS,EAGjD,IAAI,GADAuT,GAAK9V,EAAS8K,kBAAkB0K,GAC5BO,EAAI,EAAGA,EAAID,EAAGvT,OAAQwT,IAC5BH,EAAazQ,KAAK,IAAM2Q,EAAGC,GAAGnO,YAGhC,KAAI,GAAIoO,GAAI,EAAGA,EAAIR,EAAgBjT,OAAQyT,GAAK,EAC9CJ,EAAazQ,KAAK,IAAMqQ,EAAgBQ,EAAI,GAAK,IAAMR,EAAgBQ,GAI3E,IAAG5S,EAAQuS,SAAU,CAGnB,GAAIM,GAAWpT,KAAKW,IAAIX,KAAK0B,IAAInB,EAAQ6S,SAAU9S,EAAOK,KAAML,EAAOoB,KAGnE2R,EAAmBN,EAAa9I,QAGhCqJ,EAAoBnW,EAAS6I,aAAa9B,EAAW5D,GAAS8S,GAAW,EAE7EC,GAAiBxK,OAAO,EAAG,EAAG,IAAMyK,EAAkBxQ,EAAI,IAAMwQ,EAAkBtQ,GAClFqQ,EAAiB,GAAK,IAAMV,EAAgB,GAAK,IAAMA,EAAgB,GACvEU,EAAiB/Q,KAAK,IAAMqQ,EAAgBA,EAAgBjT,OAAS,GAAK,IAAM4T,EAAkBtQ,EAGlG,IAAIuQ,GAAOlB,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAGiL,EAAiBtO,KAAK,KACxBxE,EAAQsE,WAAW0O,MAAM,GAAMvU,MAChCqD,OAAUf,EAAe9B,IACxBrC,EAASmP,MAAME,IAElBtP,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,OACN5C,OAAQf,EAAe9B,GACvB+E,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASmO,IAIb,GAAGhT,EAAQsS,SAAU,CACnB,GAAIW,GAAOnB,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAG2K,EAAahO,KAAK,KACpBxE,EAAQsE,WAAW2O,MAAM,GAAMxU,MAChCqD,OAAUf,EAAe9B,IACxBrC,EAASmP,MAAME,IAElBtP,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,OACN5C,OAAQf,EAAe9B,GACvB+E,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASoO,MAMjBtW,KAAKmH,aAAaW,KAAK,WACrB1E,OAAQA,EACR4D,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAgJb,QAASkT,GAAKnV,EAAOgB,EAAMiB,EAAS4F,GAClChJ,EAASsW,KAAKrJ,MAAMN,YAAYI,KAAKhN,KACnCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GAhVJ,GAAID,IACFrF,OACEC,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,MAElC4E,OACErB,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,KAChC6E,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRkT,UAAU,EACVD,WAAW,EACXE,UAAU,EACVM,SAAU,EACVJ,YAAY,EACZ5R,IAAKzB,OACLsB,KAAMtB,OACNiB,aAAc,EACdiE,YACEyN,MAAO,gBACP7M,MAAO,WACP8M,WAAY,YACZ9S,OAAQ,YACR+T,KAAM,UACNd,MAAO,WACPa,KAAM,UACNpP,KAAM,UACNqO,UAAW,WACXzM,SAAU,cACVjB,WAAY,iBAyShB3H,GAASsW,KAAOtW,EAASsO,KAAK7N,QAC5BkM,YAAa2J,EACbtI,YAAaA,KAGf9N,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA2CA,SAASgO,GAAY5K,GACnB,GACED,GADE+R,KAEF/Q,EAAiBnE,EAAS0C,mBAAmB1C,EAASkC,aAAanC,KAAKoC,MAAOpC,KAAKoC,KAAK8E,OAAO1E,OAGlGxC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAGhGhS,EAASnD,EAASkE,UAAUnE,KAAK2B,IAAKyC,EAAgBf,EAAS,EAE/D,IAAI2D,GAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,GAE/C6D,EAASlH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW0N,YAC1DpO,EAAOjH,KAAK2B,IAAImF,KAAK,KAAK/E,SAASsB,EAAQsE,WAAW2N,WAEtDkB,EAAYvW,EAAS6I,aAAa9B,EAAW5D,GAAS,GAAI,EAE5DnD,GAAS8G,YAAYC,EAAWhH,KAAKoC,KAAM6E,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,uBAC1F1G,EAAS2I,YAAY5B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAASrD,KAAKmH,aAAcnH,KAAK2G,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAEhD,GAAImU,GAAQnU,GAAKtC,KAAKoC,KAAKG,OAAOC,OAAS,GAAK,EAE9CkU,EAAkB1P,EAAUxF,QAAU4C,EAAe9B,GAAGE,OAAS,CAEnE2S,GAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,KAG7B9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAEP,KAAI,GAAInF,GAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAAK,CAChD,GACEiU,GADEvL,EAAInL,EAAS6I,aAAa9B,EAAW5D,EAAQgB,EAAe9B,GAAII,EAKpE0I,GAAExF,GAAK8Q,EAAmBD,EAAQpT,EAAQuT,kBAE1CD,EAAMxB,EAAa7S,GAAGwE,KAAK,QACzBX,GAAIiF,EAAExF,EACNQ,GAAIoQ,EAAU1Q,EACdO,GAAI+E,EAAExF,EACNU,GAAI8E,EAAEtF,GACLzC,EAAQsE,WAAWgP,KAAK7U,MACzBf,MAASqD,EAAe9B,GAAGI,IAC1BzC,EAASmP,MAAME,KAElBtP,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,MACNhH,MAAOqD,EAAe9B,GAAGI,GACzB2E,MAAO3E,EACPuF,MAAOkN,EAAa7S,GACpB4F,QAASyO,EACTxQ,GAAIiF,EAAExF,EACNQ,GAAIoQ,EAAU1Q,EACdO,GAAI+E,EAAExF,EACNU,GAAI8E,EAAEtF,KAKZ9F,KAAKmH,aAAaW,KAAK,WACrB1E,OAAQA,EACR4D,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAwGb,QAASwT,GAAIzV,EAAOgB,EAAMiB,EAAS4F,GACjChJ,EAAS4W,IAAI3J,MAAMN,YAAYI,KAAKhN,KAClCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GArOJ,GAAID,IACFrF,OACEC,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,MAElC4E,OACErB,OAAQ,GACRyE,aACEzC,EAAG,EACHE,EAAG,GAELqC,WAAW,EACXV,UAAU,EACVF,sBAAuBtH,EAASI,KAChC6E,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRsB,KAAMtB,OACNyB,IAAKzB,OACLiB,aAAc,EACdkT,kBAAmB,GACnBjP,YACEyN,MAAO,eACP7M,MAAO,WACP8M,WAAY,YACZ9S,OAAQ,YACRoU,IAAK,SACL1P,KAAM,UACNqO,UAAW,WACXzM,SAAU,cACVjB,WAAY,iBAoMhB3H,GAAS4W,IAAM5W,EAASsO,KAAK7N,QAC3BkM,YAAaiK,EACb5I,YAAaA,KAGf9N,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAwBA,SAAS6W,GAAwBC,EAAQxO,EAAOyO,GAC9C,GAAIC,GAAa1O,EAAM3C,EAAImR,EAAOnR,CAElC,OAAGqR,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SAIX,QAAS/I,GAAY5K,GACnB,GACE2D,GACAxB,EACA0R,EACAC,EAJEhC,KAKFiC,EAAa/T,EAAQ+T,WACrBxU,EAAY3C,EAASkC,aAAanC,KAAKoC,KAGzCpC,MAAK2B,IAAM1B,EAASqB,UAAUtB,KAAKuB,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQsE,WAAWyN,OAEhGpO,EAAY/G,EAAS+F,gBAAgBhG,KAAK2B,IAAK0B,EAAS,EAAG,GAE3DmC,EAAS1C,KAAK0B,IAAIwC,EAAUxF,QAAU,EAAGwF,EAAUvF,SAAW,GAE9D0V,EAAe9T,EAAQgU,OAASzU,EAAU0U,OAAO,SAASC,EAAeC,GACvE,MAAOD,GAAgBC,GACtB,GAKHhS,GAAUnC,EAAQoU,MAAQpU,EAAQqU,WAAa,EAAK,EAIpDR,EAAc7T,EAAQoU,MAAQjS,EAASA,EAAS,EAEhD0R,GAAe7T,EAAQgF,WAevB,KAAK,GAZD0O,IACFnR,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAU,EACtCsE,EAAGkB,EAAUV,GAAKU,EAAUvF,SAAW,GAIrCkW,EAEU,IAFa3X,KAAKoC,KAAKG,OAAO+O,OAAO,SAASsG,GAC1D,MAAe,KAARA,IACNpV,OAIMF,EAAI,EAAGA,EAAItC,KAAKoC,KAAKG,OAAOC,OAAQF,IAAK,CAChD6S,EAAa7S,GAAKtC,KAAK2B,IAAImF,KAAK,IAAK,KAAM,MAAM,GAG9C9G,KAAKoC,KAAKG,OAAOD,GAAGwM,MACrBqG,EAAa7S,GAAGR,MACdyT,cAAevV,KAAKoC,KAAKG,OAAOD,GAAGwM,MAClC7O,EAASmP,MAAME,KAIpB6F,EAAa7S,GAAGP,UACdsB,EAAQsE,WAAWpF,OAClBvC,KAAKoC,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQsE,WAAWpF,OAAS,IAAMtC,EAASM,cAAc+B,IAC3FuF,KAAK,KAEP,IAAIgQ,GAAWT,EAAaxU,EAAUN,GAAK6U,EAAe,GAGvDU,GAAWT,IAAe,MAC3BS,GAAY,IAGd,IAAIC,GAAQ7X,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGN,EAAQ4R,GAAoB,IAAN9U,GAAWqV,EAAuB,EAAI,KACpHI,EAAM9X,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGN,EAAQqS,GAC5DG,EAAoC,KAAzBH,EAAWT,EAAoB,IAAM,IAChDlM,GAEE,IAAK6M,EAAInS,EAAGmS,EAAIjS,EAEhB,IAAKN,EAAQA,EAAQ,EAAGwS,EAAU,EAAGF,EAAMlS,EAAGkS,EAAMhS,EAIrDzC,GAAQoU,SAAU,GACnBvM,EAAE9F,KAAK,IAAK2R,EAAOnR,EAAGmR,EAAOjR,EAK/B,IAAImS,GAAO9C,EAAa7S,GAAGwE,KAAK,QAC9BoE,EAAGA,EAAErD,KAAK,MACTxE,EAAQsE,WAAWoF,OAAS1J,EAAQoU,MAAQ,IAAMpU,EAAQsE,WAAW8P,MAAQ,IA6BhF,IA1BAQ,EAAKnW,MACHf,MAAS6B,EAAUN,IAClBrC,EAASmP,MAAME,KAGfjM,EAAQoU,SAAU,GACnBQ,EAAKnW,MACHE,MAAS,mBAAqBqB,EAAQqU,WAAc,OAKxD1X,KAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNhH,MAAO6B,EAAUN,GACjB6U,aAAcA,EACd9P,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAAS+P,EACTlB,OAAQA,EACRvR,OAAQA,EACR4R,WAAYA,EACZS,SAAUA,IAITxU,EAAQ8E,UAAW,CAEpB,GAAIC,GAAgBnI,EAASoF,iBAAiB0R,EAAOnR,EAAGmR,EAAOjR,EAAGoR,EAAaE,GAAcS,EAAWT,GAAc,GACpH9P,EAAoBjE,EAAQkE,sBAAsBvH,KAAKoC,KAAK8E,OAASlH,KAAKoC,KAAK8E,OAAO5E,GAAKM,EAAUN,GAAIA,GAEvGgG,EAAe6M,EAAa7S,GAAGwE,KAAK,QACtCoR,GAAI9P,EAAcxC,EAClBuS,GAAI/P,EAActC,EAClBsS,cAAetB,EAAwBC,EAAQ3O,EAAe/E,EAAQgV,iBACrEhV,EAAQsE,WAAWY,OAAO9B,KAAK,GAAKa,EAGvCtH,MAAKmH,aAAaW,KAAK,QACrBC,KAAM,QACNV,MAAO/E,EACP2F,MAAOkN,EAAa7S,GACpB4F,QAASI,EACT7B,KAAM,GAAKa,EACX1B,EAAGwC,EAAcxC,EACjBE,EAAGsC,EAActC,IAMrBsR,EAAaS,EAGf7X,KAAKmH,aAAaW,KAAK,WACrBd,UAAWA,EACXrF,IAAK3B,KAAK2B,IACV0B,QAASA,IAoFb,QAASiV,GAAIlX,EAAOgB,EAAMiB,EAAS4F,GACjChJ,EAASqY,IAAIpL,MAAMN,YAAYI,KAAKhN,KAClCoB,EACAgB,EACAnC,EAASS,OAAOT,EAASS,UAAWsI,GAAiB3F,GACrD4F,GA/QJ,GAAID,IACFxH,MAAOiB,OACPhB,OAAQgB,OACRiB,aAAc,EACdiE,YACEyN,MAAO,eACP7S,OAAQ,YACRwK,MAAO,WACP0K,MAAO,WACPlP,MAAO,YAET6O,WAAY,EACZC,MAAO5U,OACPgV,OAAO,EACPC,WAAY,GACZvP,WAAW,EACXE,YAAa,EACbd,sBAAuBtH,EAASI,KAChCkY,eAAe,EACfF,eAAgB,UAgQlBpY,GAASqY,IAAMrY,EAASsO,KAAK7N,QAC3BkM,YAAa0L,EACbrK,YAAaA,EACb6I,wBAAyBA,KAG3B3W,OAAQC,SAAUH,GAGbA","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 // TODO: Make it possible to call extend with var args\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} source This object 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, source) {\n target = target || {};\n for (var prop in source) {\n if (typeof source[prop] === 'object') {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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 (defaultOptions, options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas\n /**\n * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property\n * where deltas for specific object properties can be found for the given object nesting level. For nested objects the\n * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also\n * contain a __delta__ property with the deltas of their level.\n *\n * @param {Object|Array} a Object that should be used to analyzed delta to object b\n * @param {Object|Array} b The second object where the deltas from a should be analyzed\n * @returns {Object} Delta descriptor object or null\n */\n Chartist.deltaDescriptor = function(a, b) {\n var summary = {\n added: 0,\n removed: 0,\n modified: 0\n };\n\n function findDeltasRecursively(a, b) {\n var descriptor = {\n __delta__: {}\n };\n\n // First check for removed and modified properties\n Object.keys(a).forEach(function(property) {\n if(!b.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'remove',\n property: property,\n ours: a[property]\n };\n summary.removed++;\n } else {\n if(typeof a[property] === 'object') {\n var subDescriptor = findDeltasRecursively(a[property], b[property]);\n if(subDescriptor) {\n descriptor[property] = subDescriptor;\n }\n } else {\n if(a[property] !== b[property]) {\n descriptor.__delta__[property] = {\n type: 'modify',\n property: property,\n ours: a[property],\n theirs: b[property]\n };\n summary.modified++;\n }\n }\n }\n });\n\n // Check for added properties\n Object.keys(b).forEach(function(property) {\n if(!a.hasOwnProperty(property)) {\n descriptor.__delta__[property] = {\n type: 'added',\n property: property,\n theirs: b[property]\n };\n summary.added++;\n }\n });\n\n return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null;\n }\n\n var delta = findDeltasRecursively(a, b);\n if(delta) {\n delta.__delta__.summary = summary;\n }\n\n return delta;\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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 // TODO: Remove default options parameter from optionsProvider\n this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter);\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 Chartist.extend(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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 Chartist.extend(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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n Chartist.extend(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\n\n return Chartist;\n\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist"],"mappings":";;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,UAAW,WACT,MAAQF,GAAKI,oBAAsBH,MAET,gBAAZI,SAIhBC,OAAOD,QAAUJ,IAEjBD,EAAe,SAAIC,KAErBM,KAAM,WASN,MAAOC","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\n */\n\n\n return Chartist;\n\n\n}));\n"]} \ No newline at end of file diff --git a/dist/scss/_modules.scss b/dist/scss/_modules.scss deleted file mode 100644 index 938b5eac..00000000 --- a/dist/scss/_modules.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import "http://github.com/modules/common"; -@import "http://github.com/modules/scale"; -@import "http://github.com/modules/animation"; - -// not reuqired, used ? diff --git a/dist/scss/chartist.scss b/dist/scss/chartist.scss index 1b2f8c43..2456997b 100644 --- a/dist/scss/chartist.scss +++ b/dist/scss/chartist.scss @@ -1,4 +1,3 @@ -@import "http://github.com/modules"; @import "http://github.com/settings/chartist-settings"; @mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) { diff --git a/dist/scss/modules/_animation.scss b/dist/scss/modules/_animation.scss deleted file mode 100644 index 1af626a1..00000000 --- a/dist/scss/modules/_animation.scss +++ /dev/null @@ -1,21 +0,0 @@ -@mixin keyframes($name) { - @-webkit-keyframes #{$name} { - @content; - } - @-moz-keyframes #{$name} { - @content; - } - @-ms-keyframes #{$name} { - @content; - } - @keyframes #{$name} { - @content; - } -} - -@mixin animation($name, $params) { - -webkit-animation: #{$name} $params; /* Safari 4+ */ - -moz-animation: #{$name} $params; /* Fx 5+ */ - -o-animation: #{$name} $params; /* Opera 12+ */ - animation: #{$name} $params; /* IE 10+ */ -} \ No newline at end of file diff --git a/dist/scss/modules/_common.scss b/dist/scss/modules/_common.scss deleted file mode 100644 index e29cd020..00000000 --- a/dist/scss/modules/_common.scss +++ /dev/null @@ -1,15 +0,0 @@ -@function reverse($list, $recursive: false) { - $result: (); - - @for $i from length($list)*-1 through -1 { - @if type-of(nth($list, abs($i))) == list and $recursive { - $result: append($result, reverse(nth($list, abs($i)), $recursive)); - } - - @else { - $result: append($result, nth($list, abs($i))); - } - } - - @return $result; -} \ No newline at end of file diff --git a/dist/scss/modules/_scale.scss b/dist/scss/modules/_scale.scss deleted file mode 100644 index 1a7a3b7d..00000000 --- a/dist/scss/modules/_scale.scss +++ /dev/null @@ -1,41 +0,0 @@ -$scale-minor-second: 15/16; -$scale-major-second: 8/9; -$scale-minor-third: 5/6; -$scale-major-third: 4/5; -$scale-perfect-fourth: 3/4; -$scale-perfect-fifth: 2/3; -$scale-minor-sixth: 5/8; -$scale-golden-section: 1/1.618; -$scale-major-sixth: 3/5; -$scale-minor-seventh: 9/16; -$scale-major-seventh: 8/15; -$scale-octave: 1/2; -$scale-major-tenth: 2/5; -$scale-major-eleventh: 3/8; -$scale-major-twelfth: 1/3; -$scale-double-octave: 1/4; - -@function generateScale($base: 16, $scale-type: $scale-golden-section, $limit-lower: 6, $limit-upper: 100) { - $scale: (); - $value: $base; - - @while $value > $limit-lower { - $value: $value * $scale-type; - @if $value > $limit-lower { - $scale: append($scale, $value); - } - } - - $scale: reverse($scale); - $scale: append($scale, $base); - - $value: $base; - @while $value < $limit-upper { - $value: $value / $scale-type; - @if $value < $limit-upper { - $scale: append($scale, $value); - } - } - - @return $scale; -} \ No newline at end of file From 98702ba6467009493d6624f2ba5e592291ede7d7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 12:38:34 +0100 Subject: [PATCH 103/593] Fixed usemin path --- site/layouts/default.hbs | 18 +++++++++--------- tasks/aliases.yml | 2 -- tasks/concat.js | 17 +++-------------- tasks/connect.js | 2 +- tasks/uglify.js | 8 -------- tasks/watch.js | 4 ++-- 6 files changed, 15 insertions(+), 36 deletions(-) diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 87d1fe0e..4fa7d444 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -36,7 +36,7 @@ ga('send', 'pageview'); - + @@ -51,14 +51,14 @@ - - - - - - - - + + + + + + + + diff --git a/tasks/aliases.yml b/tasks/aliases.yml index 763077fe..e35f3ebd 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -32,8 +32,6 @@ public: - 'usemin' - 'critical' - 'htmlmin' - - 'concat:public' - - 'uglify:public' # tests test: diff --git a/tasks/concat.js b/tasks/concat.js index 96306e85..e4856946 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -23,20 +23,9 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/class.js', '<%= pkg.config.src %>/base.js', '<%= pkg.config.src %>/svg.js', - '<%= pkg.config.src %>/types/line.js', - '<%= pkg.config.src %>/types/bar.js', - '<%= pkg.config.src %>/types/pie.js' - ] - } - }, - public: { - options: { - separator: ';', - }, - files: { - '<%= pkg.config.public %>/scripts/all.js': [ - '<%= pkg.config.dist %>/chartist.js', - '<%= pkg.config.public %>/scripts/all.js' + '<%= pkg.config.src %>/charts/line.js', + '<%= pkg.config.src %>/charts/bar.js', + '<%= pkg.config.src %>/charts/pie.js' ] } } diff --git a/tasks/connect.js b/tasks/connect.js index a96208d5..1d8c608c 100644 --- a/tasks/connect.js +++ b/tasks/connect.js @@ -22,7 +22,7 @@ module.exports = function (grunt) { open: true, base: [ '<%= pkg.config.tmp %>', - '<%= pkg.config.src %>/scripts', + '<%= pkg.config.src %>', '<%= pkg.config.site %>' ] } diff --git a/tasks/uglify.js b/tasks/uglify.js index b3db3cbc..8d1d09b4 100644 --- a/tasks/uglify.js +++ b/tasks/uglify.js @@ -20,14 +20,6 @@ module.exports = function (grunt) { files: { '<%= pkg.config.dist %>/chartist.min.js': ['<%= pkg.config.dist %>/chartist.js'] } - }, - public: { - options: { - banner: '<%= pkg.config.banner %>', - }, - files: { - '<%= pkg.config.public %>/scripts/all.js': ['<%= pkg.config.public %>/scripts/all.js'] - } } }; }; diff --git a/tasks/watch.js b/tasks/watch.js index 421df9e3..bf3fbc13 100644 --- a/tasks/watch.js +++ b/tasks/watch.js @@ -13,11 +13,11 @@ module.exports = function (grunt) { return { assemble: { files: ['<%= pkg.config.site %>/**/*.{hbs,yml,json,js}'], - tasks: ['doxication', 'assemble'] + tasks: ['assemble'] }, doxication: { files: ['<%= pkg.config.tmp %>/data/**/*.{yml,json}'], - tasks: ['doxication', 'assemble'] + tasks: ['assemble'] }, js: { files: [ From 3819a7d4515dc2ae7dc5453b435ea6201f539d52 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 16:15:47 +0100 Subject: [PATCH 104/593] Fixed URLs changed due to structure refactoring --- README.md | 2 +- site/styles/main.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7a5fd6e1..64af42df 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Big welcome by the Chartist Guy -![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/source/images/chartist-guy.gif "The Chartist Guy") +![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") *Checkout the documentation site at http://gionkunz.github.io/chartist-js/* diff --git a/site/styles/main.scss b/site/styles/main.scss index b1e13dec..fe3e72eb 100644 --- a/site/styles/main.scss +++ b/site/styles/main.scss @@ -121,7 +121,7 @@ code { border-radius: 50%; border: 2px solid #F4C63D; background-size: 32px 32px; - background: #F4C63D url("http://github.com/images/chartist-icon.svg") no-repeat center; + background: #F4C63D url("http://github.com/images/chartist-icon.svg") no-repeat center; } } } From 876f0516c15af7ee189e3c4473e7f1570fdc6436 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Nov 2014 17:28:28 +0100 Subject: [PATCH 105/593] Updated site and development stack dependencies to latest version and fixed some issues --- bower.json | 10 +- package.json | 26 +- site/styles/main.scss | 8 + site/styles/settings/_foundation.scss | 758 +++++++++++++++++--------- 4 files changed, 526 insertions(+), 276 deletions(-) diff --git a/bower.json b/bower.json index 54198425..7ab31eb5 100644 --- a/bower.json +++ b/bower.json @@ -6,11 +6,11 @@ "./dist/chartist.min.css" ], "devDependencies": { - "snap.svg": "~0.2.0", - "foundation": "~5.1.1", - "highlightjs": "~8.0.0", - "compass-mixins": "~1.0.0", - "codemirror": "~4.5.0", + "snap.svg": "~0.3.0", + "foundation": "~5.4.7", + "highlightjs": "~8.3.0", + "compass-mixins": "~1.0.2", + "codemirror": "~4.8.0", "base64": "~0.3.0" }, "ignore": [ diff --git a/package.json b/package.json index 36e1a7a2..3926657b 100644 --- a/package.json +++ b/package.json @@ -35,30 +35,30 @@ ], "dependencies": {}, "devDependencies": { - "assemble": "~0.4.36", + "assemble": "~0.4.42", "assemble-dox": "0.0.2", "grunt": "^0.4.5", "grunt-concurrent": "^1.0.0", "grunt-contrib-clean": "^0.6.0", "grunt-contrib-concat": "^0.5.0", - "grunt-contrib-connect": "~0.5.0", + "grunt-contrib-connect": "~0.9.0", "grunt-contrib-copy": "^0.7.0", "grunt-contrib-cssmin": "^0.10.0", - "grunt-contrib-htmlmin": "~0.1.3", - "grunt-contrib-imagemin": "~0.3.0", - "grunt-contrib-jasmine": "~0.7.0", - "grunt-contrib-jshint": "~0.7.1", + "grunt-contrib-htmlmin": "~0.3.0", + "grunt-contrib-imagemin": "~0.9.2", + "grunt-contrib-jasmine": "~0.8.1", + "grunt-contrib-jshint": "~0.10.0", "grunt-contrib-uglify": "^0.6.0", "grunt-contrib-watch": "^0.6.1", "grunt-critical": "0.0.3", "grunt-newer": "^0.8.0", - "grunt-sass": "~0.14.2", - "grunt-svgmin": "~0.2.0", - "grunt-umd": "~2.0.0", - "grunt-usemin": "~2.3.0", - "handlebars-helpers": "~0.5.5", - "jasmine-fixture": "~1.0.8", - "jshint-stylish": "~0.1.3", + "grunt-sass": "^0.16.1", + "grunt-svgmin": "~2.0.0", + "grunt-umd": "~2.2.1", + "grunt-usemin": "~2.6.2", + "handlebars-helpers": "~0.5.8", + "jasmine-fixture": "~1.2.2", + "jshint-stylish": "~1.0.0", "load-grunt-config": "^0.16.0", "lodash": "^2.4.1", "seed-random": "~2.2.0", diff --git a/site/styles/main.scss b/site/styles/main.scss index fe3e72eb..dea50f46 100644 --- a/site/styles/main.scss +++ b/site/styles/main.scss @@ -189,6 +189,14 @@ code { content: "\2013\00A0"; } } + + > li a:not(.button) { + padding: 0; + + &:hover { + background: none; + } + } } } } diff --git a/site/styles/settings/_foundation.scss b/site/styles/settings/_foundation.scss index 3147ae13..01d5026b 100644 --- a/site/styles/settings/_foundation.scss +++ b/site/styles/settings/_foundation.scss @@ -1,6 +1,55 @@ +// Foundation by ZURB +// foundation.zurb.com +// Licensed under MIT Open Source + // -// FOUNDATION SETTINGS + +// Table of Contents +// Foundation Settings // +// a. Base +// b. Grid +// c. Global +// d. Media Query Ranges +// e. Typography +// 01. Accordion +// 02. Alert Boxes +// 03. Block Grid +// 04. Breadcrumbs +// 05. Buttons +// 06. Button Groups +// 07. Clearing +// 08. Dropdown +// 09. Dropdown Buttons +// 10. Flex Video +// 11. Forms +// 12. Icon Bar +// 13. Inline Lists +// 14. Joyride +// 15. Keystrokes +// 16. Labels +// 17. Magellan +// 18. Off-canvas +// 19. Orbit +// 20. Pagination +// 21. Panels +// 22. Pricing Tables +// 23. Progress Bar +// 24. Range Slider +// 25. Reveal +// 26. Side Nav +// 27. Split Buttons +// 28. Sub Nav +// 29. Switch +// 30. Tables +// 31. Tabs +// 32. Thumbnails +// 33. Tooltips +// 34. Top Bar +// 36. Visibility Classes + +// a. Base +// - - - - - - - - - - - - - - - - - - - - - - - - - // This is the default html and body font-size for the base rem value. // $rem-base: 16px; @@ -8,8 +57,6 @@ // Allows the use of rem-calc() or lower-bound() in your settings @import "http://github.com/foundation/scss/foundation/functions"; -// $experimental: true; - // The default font-size is set to 100% of the browser style sheet (usually 16px) // for compatibility with browser-based text zoom or user-set defaults. @@ -18,28 +65,69 @@ // set $rem-base to $base-font-size and make sure $base-font-size is a px value. // $base-font-size: 100%; -// The $base-line-height is 100% while $base-font-size is 150% -$base-line-height: 150%; +// The $base-font-size is 100% while $base-line-height is 150% +// $base-line-height: 150%; // We use this to control whether or not CSS classes come through in the gem files. $include-html-classes: false; // $include-print-styles: true; $include-html-global-classes: true; -// Grid +// b. Grid +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-grid-classes: $include-html-classes; // $include-xl-html-grid-classes: false; $row-width: rem-calc(1200); -$column-gutter: rem-calc(50); $total-columns: 12; +$column-gutter: rem-calc(50); + +// c. Global +// - - - - - - - - - - - - - - - - - - - - - - - - - + +// We use these to define default font stacks +//$font-family-sans-serif: $font-body; +// $font-family-serif: Georgia, Cambria, "Times New Roman", Times, serif; +//$font-family-monospace: Consolas, "Liberation Mono", Courier, monospace; + +// We use these to define default font weights +// $font-weight-normal: normal !default; +// $font-weight-bold: bold !default; + +// $white : #FFFFFF; +// $ghost : #FAFAFA; +// $snow : #F9F9F9; +// $vapor : #F6F6F6; +// $white-smoke : #F5F5F5; +// $silver : #EFEFEF; +// $smoke : #EEEEEE; +// $gainsboro : #DDDDDD; +// $iron : #CCCCCC; +// $base : #AAAAAA; +// $aluminum : #999999; +// $jumbo : #888888; +// $monsoon : #777777; +// $steel : #666666; +// $charcoal : #555555; +// $tuatara : #444444; +// $oil : #333333; +// $jet : #222222; +// $black : #000000; + +// We use these as default colors throughout +$primary-color: $color-yellow; +$secondary-color: $color-gray; +$alert-color: $color-red; +$success-color: $color-yellow; +$warning-color: $color-grapefruit; +$info-color: $color-gray; // We use these to control various global styles $body-bg: $color-white; $body-font-color: darken($color-white, 60%); $body-font-family: $font-body; -// $body-font-weight: normal; +// $body-font-weight: $font-weight-normal; // $body-font-style: normal; // We use this to control font-smoothing @@ -49,14 +137,7 @@ $body-font-family: $font-body; // $text-direction: ltr; // $opposite-direction: right; // $default-float: left; - -// We use these as default colors throughout -$primary-color: $color-yellow; -$secondary-color: $color-gray; -$alert-color: $color-red; -$success-color: $color-yellow; -$warning-color: $color-grapefruit; -$info-color: $color-gray; +// $last-child-float: $opposite-direction; // We use these to make sure border radius matches unless we want it different. // $global-radius: 3px; @@ -64,15 +145,17 @@ $info-color: $color-gray; // We use these to control inset shadow shiny edges and depressions. // $shiny-edge-size: 0 1px 0; -// $shiny-edge-color: rgba(#fff, .5); -// $shiny-edge-active-color: rgba(#000, .2); +// $shiny-edge-color: rgba($white, .5); +// $shiny-edge-active-color: rgba($black, .2); + +// d. Media Query Ranges +// - - - - - - - - - - - - - - - - - - - - - - - - - -// Media Query Ranges $small-range: (0em, 40em); $medium-range: (40.063em, 64em); $large-range: (64.063em, 90em); $xlarge-range: (90.063em, 120em); -$xxlarge-range: (120.063em); +$xxlarge-range: (120.063em, 99999999em); $screen: "only screen"; @@ -99,24 +182,23 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // $medium: $medium-up; // $large: $large-up; -//We use this as cursors values for enabling the option of having custom cursors in the whole site's stylesheet +// We use this as cursors values for enabling the option of having custom cursors in the whole site's stylesheet // $cursor-crosshair-value: crosshair; // $cursor-default-value: default; // $cursor-pointer-value: pointer; // $cursor-help-value: help; // $cursor-text-value: text; -// -// TYPOGRAPHY -// +// e. Typography +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-type-classes: $include-html-classes; // We use these to control header font styles // $header-font-family: $body-font-family; -// $header-font-weight: 300; +// $header-font-weight: $font-weight-normal; // $header-font-style: normal; -// $header-font-color: #222; +// $header-font-color: $jet; // $header-line-height: 1.4; // $header-top-margin: .2rem; // $header-bottom-margin: .5rem; @@ -130,10 +212,18 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // $h5-font-size: rem-calc(18); // $h6-font-size: 1rem; +// We use these to control header size reduction on small screens +// $h1-font-reduction: rem-calc(10) !default; +// $h2-font-reduction: rem-calc(10) !default; +// $h3-font-reduction: rem-calc(5) !default; +// $h4-font-reduction: rem-calc(5) !default; +// $h5-font-reduction: 0 !default; +// $h6-font-reduction: 0 !default; + // These control how subheaders are styled. // $subheader-line-height: 1.4; // $subheader-font-color: scale-color($header-font-color, $lightness: 35%); -// $subheader-font-weight: 300; +// $subheader-font-weight: $font-weight-normal; // $subheader-top-margin: .2rem; // $subheader-bottom-margin: .5rem; @@ -143,7 +233,7 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // We use these to style paragraphs // $paragraph-font-family: inherit; -// $paragraph-font-weight: normal; +// $paragraph-font-weight: $font-weight-normal; // $paragraph-font-size: 1rem; // $paragraph-line-height: 1.6; // $paragraph-margin-bottom: rem-calc(20); @@ -153,41 +243,51 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // $paragraph-text-rendering: optimizeLegibility; // We use these to style tags -// $code-color: scale-color($alert-color, $lightness: -27%); -// $code-font-family: Consolas, 'Liberation Mono', Courier, monospace; -// $code-font-weight: bold; +// $code-color: $oil; +// $code-font-family: $font-family-monospace; +// $code-font-weight: $font-weight-normal; +// $code-background-color: scale-color($secondary-color, $lightness: 70%); +// $code-border-size: 1px; +// $code-border-style: solid; +// $code-border-color: scale-color($code-background-color, $lightness: -10%); +// $code-padding: rem-calc(2) rem-calc(5) rem-calc(1); // We use these to style anchors // $anchor-text-decoration: none; +// $anchor-text-decoration-hover: none; // $anchor-font-color: $primary-color; // $anchor-font-color-hover: scale-color($primary-color, $lightness: -14%); // We use these to style the
    element // $hr-border-width: 1px; // $hr-border-style: solid; -// $hr-border-color: #ddd; +// $hr-border-color: $gainsboro; // $hr-margin: rem-calc(20); // We use these to style lists +// $list-font-family: $paragraph-font-family; +// $list-font-size: $paragraph-font-size; +// $list-line-height: $paragraph-line-height; +// $list-margin-bottom: $paragraph-margin-bottom; // $list-style-position: outside; // $list-side-margin: 1.1rem; // $list-ordered-side-margin: 1.4rem; // $list-side-margin-no-bullet: 0; // $list-nested-margin: rem-calc(20); -// $definition-list-header-weight: bold; +// $definition-list-header-weight: $font-weight-bold; // $definition-list-header-margin-bottom: .3rem; // $definition-list-margin-bottom: rem-calc(12); // We use these to style blockquotes // $blockquote-font-color: scale-color($header-font-color, $lightness: 35%); // $blockquote-padding: rem-calc(9 20 0 19); -// $blockquote-border: 1px solid #ddd; +// $blockquote-border: 1px solid $gainsboro; // $blockquote-cite-font-size: rem-calc(13); // $blockquote-cite-font-color: scale-color($header-font-color, $lightness: 23%); // $blockquote-cite-link-color: $blockquote-cite-font-color; // Acronym styles -// $acronym-underline: 1px dotted #ddd; +// $acronym-underline: 1px dotted $gainsboro; // We use these to control padding and margin // $microformat-padding: rem-calc(10 12); @@ -196,38 +296,40 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // We use these to control the border styles // $microformat-border-width: 1px; // $microformat-border-style: solid; -// $microformat-border-color: #ddd; +// $microformat-border-color: $gainsboro; // We use these to control full name font styles -// $microformat-fullname-font-weight: bold; +// $microformat-fullname-font-weight: $font-weight-bold; // $microformat-fullname-font-size: rem-calc(15); // We use this to control the summary font styles -// $microformat-summary-font-weight: bold; +// $microformat-summary-font-weight: $font-weight-bold; // We use this to control abbr padding // $microformat-abbr-padding: rem-calc(0 1); // We use this to control abbr font styles -// $microformat-abbr-font-weight: bold; +// $microformat-abbr-font-weight: $font-weight-bold; // $microformat-abbr-font-decoration: none; -// Accordion +// 01. Accordion +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-accordion-classes: $include-html-classes; // $accordion-navigation-padding: rem-calc(16); -// $accordion-navigation-bg-color: #efefef ; +// $accordion-navigation-bg-color: $silver ; // $accordion-navigation-hover-bg-color: scale-color($accordion-navigation-bg-color, $lightness: -5%); // $accordion-navigation-active-bg-color: scale-color($accordion-navigation-bg-color, $lightness: -3%); -// $accordion-navigation-font-color: #222; +// $accordion-navigation-font-color: $jet; // $accordion-navigation-font-size: rem-calc(16); // $accordion-navigation-font-family: $body-font-family; // $accordion-content-padding: $column-gutter/2; -// $accordion-content-active-bg-color: #fff; +// $accordion-content-active-bg-color: $white; -// Alert Boxes +// 02. Alert Boxes +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-alert-classes: $include-html-classes; @@ -238,9 +340,9 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // $alert-padding-bottom: $alert-padding-top; // We use these to control text style. -// $alert-font-weight: normal; +// $alert-font-weight: $font-weight-normal; // $alert-font-size: rem-calc(13); -// $alert-font-color: #fff; +// $alert-font-color: $white; // $alert-font-color-alt: scale-color($secondary-color, $lightness: -66%); // We use this for close hover effect. @@ -253,9 +355,9 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // $alert-bottom-margin: rem-calc(20); // We use these to style the close buttons -// $alert-close-color: #333; +// $alert-close-color: $oil; // $alert-close-top: 50%; -// $alert-close-position: rem-calc(5); +// $alert-close-position: rem-calc(4); // $alert-close-font-size: rem-calc(22); // $alert-close-opacity: 0.3; // $alert-close-opacity-hover: 0.5; @@ -264,18 +366,26 @@ $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (m // We use this to control border radius // $alert-radius: $global-radius; -// Block Grid +// We use this to control transition effects +// $alert-transition-speed: 300ms; +// $alert-transition-ease: ease-out; -// $include-html-grid-classes: $include-html-classes; +// 03. Block Grid +// - - - - - - - - - - - - - - - - - - - - - - - - - + +// $include-html-block-grid-classes: $include-html-classes; +// $include-xl-html-block-grid-classes: false; // We use this to control the maximum number of block grid elements per row // $block-grid-elements: 12; // $block-grid-default-spacing: rem-calc(20); +// $align-block-grid-to-grid: false; // Enables media queries for block-grid classes. Set to false if writing semantic HTML. // $block-grid-media-queries: true; -// Breadcrumbs +// 04. Breadcrumbs +// - - - - - - - - - - - - - - - - - - - - - - - - - $include-html-nav-classes: $include-html-classes; @@ -296,18 +406,17 @@ $include-html-nav-classes: $include-html-classes; // We use these to set various text styles for breadcrumbs. // $crumb-font-size: rem-calc(11); // $crumb-font-color: $primary-color; -// $crumb-font-color-current: #333; -// $crumb-font-color-unavailable: #999; +// $crumb-font-color-current: $oil; +// $crumb-font-color-unavailable: $aluminum; // $crumb-font-transform: uppercase; // $crumb-link-decor: underline; // We use these to control the slash between breadcrumbs -// $crumb-slash-color: #aaa; +// $crumb-slash-color: $base; // $crumb-slash: "/"; -// -// BUTTONS -// +// 05. Buttons +// - - - - - - - - - - - - - - - - - - - - - - - - - $include-html-button-classes: true; @@ -324,29 +433,40 @@ $include-html-button-classes: true; // We use these to control button text styles. // $button-font-family: $body-font-family; $button-font-color: $color-black; -// $button-font-color-alt: #333; +// $button-font-color-alt: $oil; // $button-font-tny: rem-calc(11); // $button-font-sml: rem-calc(13); // $button-font-med: rem-calc(16); // $button-font-lrg: rem-calc(20); -// $button-font-weight: normal; +// $button-font-weight: $font-weight-normal; // $button-font-align: center; // We use these to control various hover effects. -// $button-function-factor: 5%; +// $button-function-factor: -20%; -// We use these to control button border styles. -// $button-border-width: 1px; +// We use these to control button border and hover styles. +// $button-border-width: 0px; // $button-border-style: solid; +// $button-bg-color: $primary-color; +// $button-bg-hover: scale-color($button-bg-color, $lightness: $button-function-factor); +// $button-border-color: $button-bg-hover; +// $secondary-button-bg-hover: scale-color($secondary-color, $lightness: $button-function-factor); +// $secondary-button-border-color: $secondary-button-bg-hover; +// $success-button-bg-hover: scale-color($success-color, $lightness: $button-function-factor); +// $success-button-border-color: $success-button-bg-hover; +// $alert-button-bg-hover: scale-color($alert-color, $lightness: $button-function-factor); +// $alert-button-border-color: $alert-button-bg-hover; // We use this to set the default radius used throughout the core. // $button-radius: $global-radius; // $button-round: $global-rounded; -// We use this to set default opacity for disabled buttons. +// We use this to set default opacity and cursor for disabled buttons. // $button-disabled-opacity: 0.7; +// $button-disabled-cursor: $cursor-default-value; -// Button Groups +// 06. Button Groups +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-button-classes: $include-html-classes; @@ -354,18 +474,19 @@ $button-font-color: $color-black; // $button-bar-margin-opposite: rem-calc(10); // $button-group-border-width: 1px; -// Clearing +// 07. Clearing +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-clearing-classes: $include-html-classes; // We use these to set the background colors for parts of Clearing. -// $clearing-bg: #333; +// $clearing-bg: $oil; // $clearing-caption-bg: $clearing-bg; -// $clearing-carousel-bg: rgba (51,51,51,0.8); +// $clearing-carousel-bg: rgba(51,51,51,0.8); // $clearing-img-bg: $clearing-bg; // We use these to style the close button -// $clearing-close-color: #ccc; +// $clearing-close-color: $iron; // $clearing-close-size: 30px; // We use these to style the arrows @@ -373,7 +494,7 @@ $button-font-color: $color-black; // $clearing-arrow-color: $clearing-close-color; // We use these to style captions -// $clearing-caption-font-color: #ccc; +// $clearing-caption-font-color: $iron; // $clearing-caption-font-size: 0.875em; // $clearing-caption-padding: 10px 30px 20px; @@ -383,7 +504,8 @@ $button-font-color: $color-black; // $clearing-carousel-thumb-width: 120px; // $clearing-carousel-thumb-active-border: 1px solid rgb(255,255,255); -// Dropdown +// 08. Dropdown +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-dropdown-classes: $include-html-classes; @@ -391,40 +513,56 @@ $button-font-color: $color-black; // $f-dropdown-max-width: 200px; // $f-dropdown-height: auto; // $f-dropdown-max-height: none; + +// Used for bottom position // $f-dropdown-margin-top: 2px; +// Used for right position +// $f-dropdown-margin-left: $f-dropdown-margin-top; + +// Used for left position +// $f-dropdown-margin-right: $f-dropdown-margin-top; + +// Used for top position +// $f-dropdown-margin-bottom: $f-dropdown-margin-top; + // We use this to control the background color -// $f-dropdown-bg: #fff; +// $f-dropdown-bg: $white; // We use this to set the border styles for dropdowns. // $f-dropdown-border-style: solid; // $f-dropdown-border-width: 1px; -// $f-dropdown-border-color: scale-color(#fff, $lightness: -20%); +// $f-dropdown-border-color: scale-color($white, $lightness: -20%); // We use these to style the triangle pip. // $f-dropdown-triangle-size: 6px; -// $f-dropdown-triangle-color: #fff; +// $f-dropdown-triangle-color: $white; // $f-dropdown-triangle-side-offset: 10px; // We use these to control styles for the list elements. // $f-dropdown-list-style: none; -// $f-dropdown-font-color: #555; +// $f-dropdown-font-color: $charcoal; // $f-dropdown-font-size: rem-calc(14); // $f-dropdown-list-padding: rem-calc(5, 10); // $f-dropdown-line-height: rem-calc(18); -// $f-dropdown-list-hover-bg: #eeeeee ; +// $f-dropdown-list-hover-bg: $smoke ; // $dropdown-mobile-default-float: 0; // We use this to control the styles for when the dropdown has custom content. // $f-dropdown-content-padding: rem-calc(20); -// Dropdown Buttons +// Default radius for dropdown. +// $f-dropdown-radius: $global-radius; + + +// 09. Dropdown Buttons +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-button-classes: $include-html-classes; // We use these to set the color of the pip in dropdown buttons -// $dropdown-button-pip-color: #fff; -// $dropdown-button-pip-color-alt: #333; +// $dropdown-button-pip-color: $white; +// $dropdown-button-pip-color-alt: $oil; // $button-pip-tny: rem-calc(6); // $button-pip-sml: rem-calc(7); @@ -455,7 +593,8 @@ $button-font-color: $color-black; // $dropdown-button-pip-opposite-lrg: $button-pip-lrg * 2.5; // $dropdown-button-pip-top-lrg: -$button-pip-lrg / 2 + rem-calc(3); -// Flex Video +// 10. Flex Video +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-media-classes: $include-html-classes; @@ -465,9 +604,10 @@ $button-font-color: $color-black; // $flex-video-margin-bottom: rem-calc(16); // We use this to control widescreen bottom padding -// $flex-video-widescreen-padding-bottom: 57.25%; +// $flex-video-widescreen-padding-bottom: 56.34%; -// Forms +// 11. Forms +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-form-classes: $include-html-classes; @@ -477,62 +617,85 @@ $button-font-color: $color-black; // We use these to style the labels in different ways // $form-label-pointer: pointer; // $form-label-font-size: rem-calc(14); -// $form-label-font-weight: normal; +// $form-label-font-weight: $font-weight-normal; // $form-label-line-height: 1.5; -// $form-label-font-color: scale-color(#000, $lightness: 30%); +// $form-label-font-color: scale-color($black, $lightness: 30%); +// $form-label-small-transform: capitalize; // $form-label-bottom-margin: 0; // $input-font-family: inherit; // $input-font-color: rgba(0,0,0,0.75); // $input-font-size: rem-calc(14); -// $input-bg-color: #fff; -// $input-focus-bg-color: scale-color(#fff, $lightness: -2%); -// $input-border-color: scale-color(#fff, $lightness: -20%); -// $input-focus-border-color: scale-color(#fff, $lightness: -40%); +// $input-bg-color: $white; +// $input-focus-bg-color: scale-color($white, $lightness: -2%); +// $input-border-color: scale-color($white, $lightness: -20%); +// $input-focus-border-color: scale-color($white, $lightness: -40%); // $input-border-style: solid; // $input-border-width: 1px; // $input-border-radius: $global-radius; -// $input-disabled-bg: #ddd; +// $input-disabled-bg: $gainsboro; +// $input-disabled-cursor: $cursor-default-value; // $input-box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); -// $input-include-glowing-effect: true; // We use these to style the fieldset border and spacing. // $fieldset-border-style: solid; // $fieldset-border-width: 1px; -// $fieldset-border-color: #ddd; +// $fieldset-border-color: $gainsboro; // $fieldset-padding: rem-calc(20); // $fieldset-margin: rem-calc(18 0); // We use these to style the legends when you use them -// $legend-bg: #fff; -// $legend-font-weight: bold; +// $legend-bg: $white; +// $legend-font-weight: $font-weight-bold; // $legend-padding: rem-calc(0 3); // We use these to style the prefix and postfix input elements -// $input-prefix-bg: scale-color(#fff, $lightness: -5%); -// $input-prefix-border-color: scale-color(#fff, $lightness: -20%); +// $input-prefix-bg: scale-color($white, $lightness: -5%); +// $input-prefix-border-color: scale-color($white, $lightness: -20%); // $input-prefix-border-size: 1px; // $input-prefix-border-type: solid; // $input-prefix-overflow: hidden; -// $input-prefix-font-color: #333; -// $input-prefix-font-color-alt: #fff; +// $input-prefix-font-color: $oil; +// $input-prefix-font-color-alt: $white; + +// We use this setting to turn on/off HTML5 number spinners (the up/down arrows) +// $input-number-spinners: true; // We use these to style the error states for inputs and labels // $input-error-message-padding: rem-calc(6 9 9); // $input-error-message-top: -1px; // $input-error-message-font-size: rem-calc(12); -// $input-error-message-font-weight: normal; +// $input-error-message-font-weight: $font-weight-normal; // $input-error-message-font-style: italic; -// $input-error-message-font-color: #fff; -// $input-error-message-font-color-alt: #333; +// $input-error-message-font-color: $white; +// $input-error-message-font-color-alt: $oil; // We use this to style the glowing effect of inputs when focused +// $input-include-glowing-effect: true; // $glowing-effect-fade-time: 0.45s; // $glowing-effect-color: $input-focus-border-color; // Select variables -// $select-bg-color: #fafafa; - -// Inline Lists +// $select-bg-color: $ghost; +// $select-hover-bg-color: scale-color($select-bg-color, $lightness: -3%); + +// 12. Icon Bar +// - - - - - - - - - - - - - - - - - - - - - - - - - + +// We use these to style the icon-bar and items +// $include-html-icon-bar-classes: $include-html-classes; +// $icon-bar-bg: $oil; +// $icon-bar-font-color: $white; +// $icon-bar-font-size: 1rem; +// $icon-bar-hover-color: $primary-color; +// $icon-bar-icon-color: $white; +// $icon-bar-icon-size: 1.875rem; +// $icon-bar-image-width: 1.875rem; +// $icon-bar-image-height: 1.875rem; +// $icon-bar-active-color: $primary-color; +// $icon-bar-item-padding: 1.25rem; + +// 13. Inline Lists +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-inline-list-classes: $include-html-classes; @@ -541,6 +704,7 @@ $button-font-color: $color-black; // $inline-list-opposite-margin: 0; // $inline-list-bottom-margin: rem-calc(17); // $inline-list-default-float-margin: rem-calc(-22); +// $inline-list-default-float-list-margin: rem-calc(22); // $inline-list-padding: 0; @@ -550,25 +714,26 @@ $button-font-color: $color-black; // We use this to control the list items // $inline-list-display: block; -// We use this to control any elments within list items +// We use this to control any elements within list items // $inline-list-children-display: block; -// Joyride +// 14. Joyride +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-joyride-classes: $include-html-classes; // Controlling default Joyride styles -// $joyride-tip-bg: #333; +// $joyride-tip-bg: $oil; // $joyride-tip-default-width: 300px; // $joyride-tip-padding: rem-calc(18 20 24); -// $joyride-tip-border: solid 1px #555; +// $joyride-tip-border: solid 1px $charcoal; // $joyride-tip-radius: 4px; // $joyride-tip-position-offset: 22px; -// Here, we're setting the tip dont styles -// $joyride-tip-font-color: #fff; +// Here, we're setting the tip font styles +// $joyride-tip-font-color: $white; // $joyride-tip-font-size: rem-calc(14); -// $joyride-tip-header-weight: bold; +// $joyride-tip-header-weight: $font-weight-bold; // This changes the nub size // $joyride-tip-nub-size: 10px; @@ -576,65 +741,72 @@ $button-font-color: $color-black; // This adjusts the styles for the timer when its enabled // $joyride-tip-timer-width: 50px; // $joyride-tip-timer-height: 3px; -// $joyride-tip-timer-color: #666; +// $joyride-tip-timer-color: $steel; // This changes up the styles for the close button -// $joyride-tip-close-color: #777; +// $joyride-tip-close-color: $monsoon; // $joyride-tip-close-size: 24px; -// $joyride-tip-close-weight: normal; +// $joyride-tip-close-weight: $font-weight-normal; // When Joyride is filling the screen, we use this style for the bg // $joyride-screenfill: rgba(0,0,0,0.5); -// Keystrokes +// 15. Keystrokes +// - - - - - - - - - - - - - - - - - - - - - - - - - -// $include-html-type-classes: $include-html-classes; +// $include-html-keystroke-classes: $include-html-classes; // We use these to control text styles. // $keystroke-font: "Consolas", "Menlo", "Courier", monospace; -// $keystroke-font-size: rem-calc(14); -// $keystroke-font-color: #222; -// $keystroke-font-color-alt: #fff; +// $keystroke-font-size: inherit; +// $keystroke-font-color: $jet; +// $keystroke-font-color-alt: $white; // $keystroke-function-factor: -7%; // We use this to control keystroke padding. // $keystroke-padding: rem-calc(2 4 0); // We use these to control background and border styles. -// $keystroke-bg: scale-color(#fff, $lightness: $keystroke-function-factor); +// $keystroke-bg: scale-color($white, $lightness: $keystroke-function-factor); // $keystroke-border-style: solid; // $keystroke-border-width: 1px; // $keystroke-border-color: scale-color($keystroke-bg, $lightness: $keystroke-function-factor); // $keystroke-radius: $global-radius; -// Labels +// 16. Labels +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-label-classes: $include-html-classes; // We use these to style the labels -// $label-padding: rem-calc(4 8 6); +// $label-padding: rem-calc(4 8 4); // $label-radius: $global-radius; // We use these to style the label text // $label-font-sizing: rem-calc(11); -// $label-font-weight: normal; -// $label-font-color: #333; -// $label-font-color-alt: #fff; +// $label-font-weight: $font-weight-normal; +// $label-font-color: $oil; +// $label-font-color-alt: $white; // $label-font-family: $body-font-family; -// Magellan +// 17. Magellan +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-magellan-classes: $include-html-classes; -// $magellan-bg: #fff; -// $magellan-padding: 10px; +// $magellan-bg: $white; +// $magellan-padding: 0 !important; + +// 18. Off-canvas +// - - - - - - - - - - - - - - - - - - - - - - - - - -// Off-canvas +// $include-html-off-canvas-classes: $include-html-classes; -// $tabbar-bg: #333; +// $tabbar-bg: $oil; // $tabbar-height: rem-calc(45); +// $tabbar-icon-width: $tabbar-height; // $tabbar-line-height: $tabbar-height; -// $tabbar-color: #FFF; +// $tabbar-color: $white; // $tabbar-middle-padding: 0 rem-calc(10); // Off Canvas Divider Styles @@ -642,92 +814,108 @@ $button-font-color: $color-black; // $tabbar-left-section-border: solid 1px scale-color($tabbar-bg, $lightness: -50%); // Off Canvas Tab Bar Headers -// $tabbar-header-color: #FFF; -// $tabbar-header-weight: bold; +// $tabbar-header-color: $white; +// $tabbar-header-weight: $font-weight-bold; // $tabbar-header-line-height: $tabbar-height; // $tabbar-header-margin: 0; // Off Canvas Menu Variables -// $off-canvas-width: 250px; -// $off-canvas-bg: #333; +// $off-canvas-width: rem-calc(250); +// $off-canvas-bg: $oil; +// $off-canvas-bg-hover: scale-color($tabbar-bg, $lightness: -30%); // Off Canvas Menu List Variables // $off-canvas-label-padding: 0.3rem rem-calc(15); -// $off-canvas-label-color: #999; +// $off-canvas-label-color: $aluminum; // $off-canvas-label-text-transform: uppercase; -// $off-canvas-label-font-weight: bold; -// $off-canvas-label-bg: #444; -// $off-canvas-label-border-top: 1px solid scale-color(#444, $lightness: 14%); +// $off-canvas-label-font-size: rem-calc(12); +// $off-canvas-label-font-weight: $font-weight-bold; +// $off-canvas-label-bg: $tuatara; +// $off-canvas-label-border-top: 1px solid scale-color($tuatara, $lightness: 14%); // $off-canvas-label-border-bottom: none; // $off-canvas-label-margin:0; // $off-canvas-link-padding: rem-calc(10, 15); -// $off-canvas-link-color: rgba(#FFF, 0.7); +// $off-canvas-link-color: rgba($white, 0.7); // $off-canvas-link-border-bottom: 1px solid scale-color($off-canvas-bg, $lightness: -25%); +// $off-canvas-back-bg: $tuatara; +// $off-canvas-back-border-top: $off-canvas-label-border-top; +// $off-canvas-back-border-bottom: $off-canvas-label-border-bottom; +// $off-canvas-back-hover-bg: scale-color($off-canvas-back-bg, $lightness: -30%); +// $off-canvas-back-hover-border-top: 1px solid scale-color($off-canvas-label-bg, $lightness: 14%); +// $off-canvas-back-hover-border-bottom: none; // Off Canvas Menu Icon Variables -// $tabbar-menu-icon-color: #FFF; +// $tabbar-menu-icon-color: $white; // $tabbar-menu-icon-hover: scale-color($tabbar-menu-icon-color, $lightness: -30%); // $tabbar-menu-icon-text-indent: rem-calc(35); // $tabbar-menu-icon-width: $tabbar-height; // $tabbar-menu-icon-height: $tabbar-height; -// $tabbar-menu-icon-line-height: rem-calc(33); // $tabbar-menu-icon-padding: 0; // $tabbar-hamburger-icon-width: rem-calc(16); -// $tabbar-hamburger-icon-left: rem-calc(13); -// $tabbar-hamburger-icon-top: rem-calc(5); +// $tabbar-hamburger-icon-left: false; +// $tabbar-hamburger-icon-top: false; +// $tabbar-hamburger-icon-thickness: 1px; +// $tabbar-hamburger-icon-gap: 6px; // Off Canvas Back-Link Overlay // $off-canvas-overlay-transition: background 300ms ease; // $off-canvas-overlay-cursor: pointer; -// $off-canvas-overlay-box-shadow: -4px 0 4px rgba(#000, 0.5), 4px 0 4px rgba(#000, 0.5); -// $off-canvas-overlay-background: rgba(#FFF, 0.2); -// $off-canvas-overlay-background-hover: rgba(#FFF, 0.05); +// $off-canvas-overlay-box-shadow: -4px 0 4px rgba($black, 0.5), 4px 0 4px rgba($black, 0.5); +// $off-canvas-overlay-background: rgba($white, 0.2); +// $off-canvas-overlay-background-hover: rgba($white, 0.05); // Transition Variables // $menu-slide: "transform 500ms ease"; -// Orbit +// 19. Orbit +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-orbit-classes: $include-html-classes; // We use these to control the caption styles // $orbit-container-bg: none; // $orbit-caption-bg: rgba(51,51,51, 0.8); -// $orbit-caption-font-color: #fff; +// $orbit-caption-font-color: $white; // $orbit-caption-font-size: rem-calc(14); // $orbit-caption-position: "bottom"; // Supported values: "bottom", "under" // $orbit-caption-padding: rem-calc(10 14); // $orbit-caption-height: auto; // We use these to control the left/right nav styles -// $orbit-nav-bg: none; +// $orbit-nav-bg: transparent; // $orbit-nav-bg-hover: rgba(0,0,0,0.3); -// $orbit-nav-arrow-color: #fff; -// $orbit-nav-arrow-color-hover: #fff; +// $orbit-nav-arrow-color: $white; +// $orbit-nav-arrow-color-hover: $white; // We use these to control the timer styles // $orbit-timer-bg: rgba(255,255,255,0.3); // $orbit-timer-show-progress-bar: true; // We use these to control the bullet nav styles -// $orbit-bullet-nav-color: #ccc; -// $orbit-bullet-nav-color-active: #999; +// $orbit-bullet-nav-color: $iron; +// $orbit-bullet-nav-color-active: $aluminum; // $orbit-bullet-radius: rem-calc(9); // We use these to controls the style of slide numbers // $orbit-slide-number-bg: rgba(0,0,0,0); -// $orbit-slide-number-font-color: #fff; +// $orbit-slide-number-font-color: $white; // $orbit-slide-number-padding: rem-calc(5); +// Hide controls on small +// $orbit-nav-hide-for-small: true; +// $orbit-bullet-hide-for-small: true; +// $orbit-timer-hide-for-small: true; + // Graceful Loading Wrapper and preloader // $wrapper-class: "slideshow-wrapper"; // $preloader-class: "preloader"; -// Pagination +// 20. Pagination +// - - - - - - - - - - - - - - - - - - - - - - - - - -// $include-html-nav-classes: $include-html-classes; +// $include-pagination-classes: $include-html-classes; // We use these to control the pagination container // $pagination-height: rem-calc(24); @@ -736,33 +924,34 @@ $button-font-color: $color-black; // We use these to set the list-item properties // $pagination-li-float: $default-float; // $pagination-li-height: rem-calc(24); -// $pagination-li-font-color: #222; +// $pagination-li-font-color: $jet; // $pagination-li-font-size: rem-calc(14); // $pagination-li-margin: rem-calc(5); // We use these for the pagination anchor links // $pagination-link-pad: rem-calc(1 10 1); -// $pagination-link-font-color: #999; -// $pagination-link-active-bg: scale-color(#fff, $lightness: -10%); +// $pagination-link-font-color: $aluminum; +// $pagination-link-active-bg: scale-color($white, $lightness: -10%); // We use these for disabled anchor links // $pagination-link-unavailable-cursor: default; -// $pagination-link-unavailable-font-color: #999; +// $pagination-link-unavailable-font-color: $aluminum; // $pagination-link-unavailable-bg-active: transparent; // We use these for currently selected anchor links // $pagination-link-current-background: $primary-color; -// $pagination-link-current-font-color: #fff; -// $pagination-link-current-font-weight: bold; +// $pagination-link-current-font-color: $white; +// $pagination-link-current-font-weight: $font-weight-bold; // $pagination-link-current-cursor: default; // $pagination-link-current-active-bg: $primary-color; -// Panels +// 21. Panels +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-panel-classes: $include-html-classes; // We use these to control the background and border styles -// $panel-bg: scale-color(#fff, $lightness: -5%); +// $panel-bg: scale-color($white, $lightness: -5%); // $panel-border-style: solid; // $panel-border-size: 1px; @@ -775,74 +964,75 @@ $button-font-color: $color-black; // $panel-padding: rem-calc(20); // We use these to set default font colors -// $panel-font-color: #333; -// $panel-font-color-alt: #fff; +// $panel-font-color: $oil; +// $panel-font-color-alt: $white; // $panel-header-adjust: true; // $callout-panel-link-color: $primary-color; -// Pricing Tables +// 22. Pricing Tables +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-pricing-classes: $include-html-classes; // We use this to control the border color -// $price-table-border: solid 1px #ddd; +// $price-table-border: solid 1px $gainsboro; // We use this to control the bottom margin of the pricing table // $price-table-margin-bottom: rem-calc(20); // We use these to control the title styles -// $price-title-bg: #333; +// $price-title-bg: $oil; // $price-title-padding: rem-calc(15 20); // $price-title-align: center; -// $price-title-color: #eee; -// $price-title-weight: normal; +// $price-title-color: $smoke; +// $price-title-weight: $font-weight-normal; // $price-title-size: rem-calc(16); // $price-title-font-family: $body-font-family; // We use these to control the price styles -// $price-money-bg: #f6f6f6 ; +// $price-money-bg: $vapor ; // $price-money-padding: rem-calc(15 20); // $price-money-align: center; -// $price-money-color: #333; -// $price-money-weight: normal; +// $price-money-color: $oil; +// $price-money-weight: $font-weight-normal; // $price-money-size: rem-calc(32); // $price-money-font-family: $body-font-family; - // We use these to control the description styles -// $price-bg: #fff; -// $price-desc-color: #777; +// $price-bg: $white; +// $price-desc-color: $monsoon; // $price-desc-padding: rem-calc(15); // $price-desc-align: center; // $price-desc-font-size: rem-calc(12); -// $price-desc-weight: normal; +// $price-desc-weight: $font-weight-normal; // $price-desc-line-height: 1.4; -// $price-desc-bottom-border: dotted 1px #ddd; +// $price-desc-bottom-border: dotted 1px $gainsboro; // We use these to control the list item styles -// $price-item-color: #333; +// $price-item-color: $oil; // $price-item-padding: rem-calc(15); // $price-item-align: center; // $price-item-font-size: rem-calc(14); -// $price-item-weight: normal; -// $price-item-bottom-border: dotted 1px #ddd; +// $price-item-weight: $font-weight-normal; +// $price-item-bottom-border: dotted 1px $gainsboro; // We use these to control the CTA area styles -// $price-cta-bg: #fff; +// $price-cta-bg: $white; // $price-cta-align: center; // $price-cta-padding: rem-calc(20 20 0); -// Progress Meters +// 23. Progress Bar +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-media-classes: $include-html-classes; -// We use this to se the prog bar height +// We use this to set the progress bar height // $progress-bar-height: rem-calc(25); -// $progress-bar-color: #f6f6f6 ; +// $progress-bar-color: $vapor ; // We use these to control the border styles -// $progress-bar-border-color: scale-color(#fff, $lightness: -20%); +// $progress-bar-border-color: scale-color($white, $lightness: 20%); // $progress-bar-border-size: 1px; // $progress-bar-border-style: solid; // $progress-bar-border-radius: $global-radius; @@ -857,37 +1047,77 @@ $button-font-color: $color-black; // $progress-meter-success-color: $success-color; // $progress-meter-alert-color: $alert-color; -// Reveal +// 24. Range Slider +// - - - - - - - - - - - - - - - - - - - - - - - - - + +// $include-html-range-slider-classes: $include-html-classes; + +// These variables define the slider bar styles +// $range-slider-bar-width: 100%; +// $range-slider-bar-height: rem-calc(16); + +// $range-slider-bar-border-width: 1px; +// $range-slider-bar-border-style: solid; +// $range-slider-bar-border-color: $gainsboro; +// $range-slider-radius: $global-radius; +// $range-slider-round: $global-rounded; +// $range-slider-bar-bg-color: $ghost; + +// Vertical bar styles +// $range-slider-vertical-bar-width: rem-calc(16); +// $range-slider-vertical-bar-height: rem-calc(200); + +// These variables define the slider handle styles +// $range-slider-handle-width: rem-calc(32); +// $range-slider-handle-height: rem-calc(22); +// $range-slider-handle-position-top: rem-calc(-5); +// $range-slider-handle-bg-color: $primary-color; +// $range-slider-handle-border-width: 1px; +// $range-slider-handle-border-style: solid; +// $range-slider-handle-border-color: none; +// $range-slider-handle-radius: $global-radius; +// $range-slider-handle-round: $global-rounded; +// $range-slider-handle-bg-hover-color: scale-color($primary-color, $lightness: -12%); +// $range-slider-handle-cursor: pointer; + +// 25. Reveal +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-reveal-classes: $include-html-classes; // We use these to control the style of the reveal overlay. -// $reveal-overlay-bg: rgba(#000, .45); -// $reveal-overlay-bg-old: #000; +// $reveal-overlay-bg: rgba($black, .45); +// $reveal-overlay-bg-old: $black; // We use these to control the style of the modal itself. -// $reveal-modal-bg: #fff; -// $reveal-position-top: 50px; +// $reveal-modal-bg: $white; +// $reveal-position-top: rem-calc(100); // $reveal-default-width: 80%; +// $reveal-max-width: $row-width; // $reveal-modal-padding: rem-calc(20); -// $reveal-box-shadow: 0 0 10px rgba(#000,.4); +// $reveal-box-shadow: 0 0 10px rgba($black,.4); // We use these to style the reveal close button -// $reveal-close-font-size: rem-calc(22); +// $reveal-close-font-size: rem-calc(40); // $reveal-close-top: rem-calc(8); // $reveal-close-side: rem-calc(11); -// $reveal-close-color: #aaa; -// $reveal-close-weight: bold; +// $reveal-close-color: $base; +// $reveal-close-weight: $font-weight-bold; + +// We use this to set the default radius used throughout the core. +// $reveal-radius: $global-radius; +// $reveal-round: $global-rounded; // We use these to control the modal border // $reveal-border-style: solid; // $reveal-border-width: 1px; -// $reveal-border-color: #666; +// $reveal-border-color: $steel; // $reveal-modal-class: "reveal-modal"; // $close-reveal-modal-class: "close-reveal-modal"; -// Side Nav +// 26. Side Nav +// - - - - - - - - - - - - - - - - - - - - - - - - - $include-html-nav-classes: true; @@ -908,21 +1138,26 @@ $side-nav-font-weight: normal; $side-nav-font-family: $body-font-family; $side-nav-active-font-family: $side-nav-font-family; - +// We use these to control heading styles. +// $side-nav-heading-color: $side-nav-link-color; +// $side-nav-heading-font-size: $side-nav-font-size; +// $side-nav-heading-font-weight: bold; +// $side-nav-heading-text-transform: uppercase; // We use these to control border styles $side-nav-divider-size: 1px; $side-nav-divider-style: solid; $side-nav-divider-color: scale-color(#fff, $lightness: -10%); -// Split Buttons +// 27. Split Buttons +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-button-classes: $include-html-classes; // We use these to control different shared styles for Split Buttons // $split-button-function-factor: 10%; -// $split-button-pip-color: #fff; -// $split-button-pip-color-alt: #333; +// $split-button-pip-color: $white; +// $split-button-pip-color-alt: $oil; // $split-button-active-bg-tint: rgba(0,0,0,0.1); // We use these to control tiny split buttons @@ -953,7 +1188,8 @@ $side-nav-divider-color: scale-color(#fff, $lightness: -10%); // $split-button-pip-top-lrg: $button-pip-lrg + rem-calc(5); // $split-button-pip-default-float-lrg: rem-calc(-6); -// Sub Nav +// 28. Sub Nav +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-nav-classes: $include-html-classes; @@ -964,42 +1200,40 @@ $side-nav-divider-color: scale-color(#fff, $lightness: -10%); // We use this to control the definition // $sub-nav-font-family: $body-font-family; // $sub-nav-font-size: rem-calc(14); -// $sub-nav-font-color: #999; -// $sub-nav-font-weight: normal; +// $sub-nav-font-color: $aluminum; +// $sub-nav-font-weight: $font-weight-normal; // $sub-nav-text-decoration: none; +// $sub-nav-padding: rem-calc(3 16); // $sub-nav-border-radius: 3px; // $sub-nav-font-color-hover: scale-color($sub-nav-font-color, $lightness: -25%); - // We use these to control the active item styles - -// $sub-nav-active-font-weight: normal; +// $sub-nav-active-font-weight: $font-weight-normal; // $sub-nav-active-bg: $primary-color; // $sub-nav-active-bg-hover: scale-color($sub-nav-active-bg, $lightness: -14%); -// $sub-nav-active-color: #fff; -// $sub-nav-active-padding: rem-calc(3 16); +// $sub-nav-active-color: $white; +// $sub-nav-active-padding: $sub-nav-padding; // $sub-nav-active-cursor: default; // $sub-nav-item-divider: ""; // $sub-nav-item-divider-margin: rem-calc(12); -// -// SWITCH -// +// 29. Switch +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-form-classes: $include-html-classes; // Controlling border styles and background colors for the switch container -// $switch-border-color: scale-color(#fff, $lightness: -20%); +// $switch-border-color: scale-color($white, $lightness: -20%); // $switch-border-style: solid; // $switch-border-width: 1px; -// $switch-bg: #fff; +// $switch-bg: $white; // We use these to control the switch heights for our default classes -// $switch-height-tny: 22px; -// $switch-height-sml: 28px; -// $switch-height-med: 36px; -// $switch-height-lrg: 44px; +// $switch-height-tny: rem-calc(22); +// $switch-height-sml: rem-calc(28); +// $switch-height-med: rem-calc(36); +// $switch-height-lrg: rem-calc(44); // $switch-bottom-margin: rem-calc(20); // We use these to control default font sizes for our classes. @@ -1010,7 +1244,7 @@ $side-nav-divider-color: scale-color(#fff, $lightness: -10%); // $switch-label-side-padding: 6px; // We use these to style the switch-paddle -// $switch-paddle-bg: #fff; +// $switch-paddle-bg: $white; // $switch-paddle-fade-to-color: scale-color($switch-paddle-bg, $lightness: -10%); // $switch-paddle-border-color: scale-color($switch-paddle-bg, $lightness: -35%); // $switch-paddle-border-width: 1px; @@ -1018,52 +1252,54 @@ $side-nav-divider-color: scale-color(#fff, $lightness: -10%); // $switch-paddle-transition-speed: .1s; // $switch-paddle-transition-ease: ease-out; // $switch-positive-color: scale-color($success-color, $lightness: 94%); -// $switch-negative-color: #f5f5f5; +// $switch-negative-color: $white-smoke; // Outline Style for tabbing through switches -// $switch-label-outline: 1px dotted #888; +// $switch-label-outline: 1px dotted $jumbo; -// Tables +// 30. Tables +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-table-classes: $include-html-classes; // These control the background color for the table and even rows -// $table-bg: #fff; -// $table-even-row-bg: #f9f9f9 ; +// $table-bg: $white; +// $table-even-row-bg: $snow ; // These control the table cell border style // $table-border-style: solid; // $table-border-size: 1px; -// $table-border-color: #ddd; +// $table-border-color: $gainsboro; // These control the table head styles -// $table-head-bg: #f5f5f5 ; +// $table-head-bg: $white-smoke ; // $table-head-font-size: rem-calc(14); -// $table-head-font-color: #222; -// $table-head-font-weight: bold; +// $table-head-font-color: $jet; +// $table-head-font-weight: $font-weight-bold; // $table-head-padding: rem-calc(8 10 10); // These control the row padding and font styles // $table-row-padding: rem-calc(9 10); // $table-row-font-size: rem-calc(14); -// $table-row-font-color: #222; +// $table-row-font-color: $jet; // $table-line-height: rem-calc(18); -// These are for controlling the display and margin of tables +// These are for controlling the layout, display and margin of tables +// $table-layout: auto; // $table-display: table-cell; // $table-margin-bottom: rem-calc(20); -// -// TABS -// +// 31. Tabs +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-tabs-classes: $include-html-classes; // $tabs-navigation-padding: rem-calc(16); -// $tabs-navigation-bg-color: #efefef ; -// $tabs-navigation-active-bg-color: #fff; +// $tabs-navigation-bg-color: $silver ; +// $tabs-navigation-active-bg-color: $white; // $tabs-navigation-hover-bg-color: scale-color($tabs-navigation-bg-color, $lightness: -6%); -// $tabs-navigation-font-color: #222; +// $tabs-navigation-font-color: $jet; +// $tabs-navigation-active-font-color: $tabs-navigation-font-color; // $tabs-navigation-font-size: rem-calc(16); // $tabs-navigation-font-family: $body-font-family; @@ -1072,53 +1308,51 @@ $side-nav-divider-color: scale-color(#fff, $lightness: -10%); // $tabs-vertical-navigation-margin-bottom: 1.25rem; -// -// THUMBNAILS -// +// 32. Thumbnails +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-media-classes: $include-html-classes; // We use these to control border styles // $thumb-border-style: solid; // $thumb-border-width: 4px; -// $thumb-border-color: #fff; -// $thumb-box-shadow: 0 0 0 1px rgba(#000,.2); +// $thumb-border-color: $white; +// $thumb-box-shadow: 0 0 0 1px rgba($black,.2); // $thumb-box-shadow-hover: 0 0 6px 1px rgba($primary-color,0.5); // Radius and transition speed for thumbs // $thumb-radius: $global-radius; // $thumb-transition-speed: 200ms; -// -// TOOLTIPS -// +// 33. Tooltips +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-tooltip-classes: $include-html-classes; -// $has-tip-border-bottom: dotted 1px #ccc; -// $has-tip-font-weight: bold; -// $has-tip-font-color: #333; +// $has-tip-border-bottom: dotted 1px $iron; +// $has-tip-font-weight: $font-weight-bold; +// $has-tip-font-color: $oil; // $has-tip-border-bottom-hover: dotted 1px scale-color($primary-color, $lightness: -55%); // $has-tip-font-color-hover: $primary-color; // $has-tip-cursor-type: help; // $tooltip-padding: rem-calc(12); -// $tooltip-bg: #333; +// $tooltip-bg: $oil; // $tooltip-font-size: rem-calc(14); -// $tooltip-font-weight: normal; -// $tooltip-font-color: #fff; +// $tooltip-font-weight: $font-weight-normal; +// $tooltip-font-color: $white; // $tooltip-line-height: 1.3; // $tooltip-close-font-size: rem-calc(10); -// $tooltip-close-font-weight: normal; -// $tooltip-close-font-color: #777; +// $tooltip-close-font-weight: $font-weight-normal; +// $tooltip-close-font-color: $monsoon; // $tooltip-font-size-sml: rem-calc(14); // $tooltip-radius: $global-radius; // $tooltip-rounded: $global-rounded; // $tooltip-pip-size: 5px; +// $tooltip-max-width: 300px; -// -// TOP BAR -// +// 34. Top Bar +// - - - - - - - - - - - - - - - - - - - - - - - - - $include-html-top-bar-classes: true; @@ -1155,6 +1389,12 @@ $topbar-link-bg-hover: #272727; $topbar-link-bg-active: $color-red; $topbar-link-bg-active-hover: scale-color($color-red, $lightness: -14%); $topbar-link-font-family: $body-font-family; +// $topbar-link-text-transform: none; +// $topbar-link-padding: $topbar-height / 3; +// $topbar-back-link-size: $h5-font-size; +// $topbar-link-dropdown-padding: 20px; + +// $topbar-button-top: 7px; $topbar-button-font-size: 0.75rem; @@ -1187,8 +1427,10 @@ $topbar-divider-border-top: solid 1px scale-color($topbar-bg-color, $lightness: $topbar-sticky-class: ".sticky"; $topbar-arrows: true; //Set false to remove the triangle icon from the menu item -// -// VISIBILITY CLASSES -// +// 36. Visibility Classes +// - - - - - - - - - - - - - - - - - - - - - - - - - // $include-html-visibility-classes: $include-html-classes; +// $include-table-visibility-classes: true; +// $include-legacy-visibility-classes: true; +// $include-accessibility-classes: true; From daf29bdd2e1760a563e30839fa3043c4b4ba17b6 Mon Sep 17 00:00:00 2001 From: Daniel Diekmeier Date: Wed, 26 Nov 2014 14:57:37 +0100 Subject: [PATCH 106/593] fix small error in setup instructions --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11e3eeb1..aa53b62a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ You will need the following to run a local development enviroment. 1. `cd` into your local copy of the repository. 2. Run `npm install` to install dependencies located in `package.json`. 3. Run `bower install` to install bower dependencies. -5. Run `grunt serve` to start the watch task, and the web server should automatically open. Congrats, you should now be able to see your local copy of the demo site. +5. Run `grunt preview` to start the watch task, and the web server should automatically open. Congrats, you should now be able to see your local copy of the demo site. ## Submission Guidelines From 0a6aae6d36a65f108d6d207d4d4d4a68ba9fe32d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 26 Nov 2014 15:14:45 +0100 Subject: [PATCH 107/593] Update CONTRIBUTING.md Fixed task name for development --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11e3eeb1..f96a4ba6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ You will need the following to run a local development enviroment. 1. `cd` into your local copy of the repository. 2. Run `npm install` to install dependencies located in `package.json`. 3. Run `bower install` to install bower dependencies. -5. Run `grunt serve` to start the watch task, and the web server should automatically open. Congrats, you should now be able to see your local copy of the demo site. +5. Run `grunt dev` to start the watch task, and the web server should automatically open. Congrats, you should now be able to see your local copy of the demo site. ## Submission Guidelines From 4a01f83e6cd4c4353a67954183683f5376f2e9ac Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 26 Nov 2014 20:27:52 +0100 Subject: [PATCH 108/593] Remove delta analysis helper until we really need it --- src/scripts/core.js | 75 --------------------------------------------- 1 file changed, 75 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 7b37c5a1..0fcc9f89 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -647,81 +647,6 @@ var Chartist = { }; }; - //TODO: For arrays it would be better to take the sequence into account and try to minimize modify deltas - /** - * This method will analyze deltas recursively in two objects. The returned object will contain a __delta__ property - * where deltas for specific object properties can be found for the given object nesting level. For nested objects the - * resulting delta descriptor object will contain properties to reflect the nesting. Nested descriptor objects also - * contain a __delta__ property with the deltas of their level. - * - * @param {Object|Array} a Object that should be used to analyzed delta to object b - * @param {Object|Array} b The second object where the deltas from a should be analyzed - * @returns {Object} Delta descriptor object or null - */ - Chartist.deltaDescriptor = function(a, b) { - var summary = { - added: 0, - removed: 0, - modified: 0 - }; - - function findDeltasRecursively(a, b) { - var descriptor = { - __delta__: {} - }; - - // First check for removed and modified properties - Object.keys(a).forEach(function(property) { - if(!b.hasOwnProperty(property)) { - descriptor.__delta__[property] = { - type: 'remove', - property: property, - ours: a[property] - }; - summary.removed++; - } else { - if(typeof a[property] === 'object') { - var subDescriptor = findDeltasRecursively(a[property], b[property]); - if(subDescriptor) { - descriptor[property] = subDescriptor; - } - } else { - if(a[property] !== b[property]) { - descriptor.__delta__[property] = { - type: 'modify', - property: property, - ours: a[property], - theirs: b[property] - }; - summary.modified++; - } - } - } - }); - - // Check for added properties - Object.keys(b).forEach(function(property) { - if(!a.hasOwnProperty(property)) { - descriptor.__delta__[property] = { - type: 'added', - property: property, - theirs: b[property] - }; - summary.added++; - } - }); - - return (Object.keys(descriptor).length !== 1 || Object.keys(descriptor.__delta__).length > 0) ? descriptor : null; - } - - var delta = findDeltasRecursively(a, b); - if(delta) { - delta.__delta__.summary = summary; - } - - return delta; - }; - //http://schepers.cc/getting-to-the-point Chartist.catmullRom2bezier = function (crp, z) { var d = []; From 25642c44cf5a5d0bafabc214ab73b78d2289c4e1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 01:17:44 +0100 Subject: [PATCH 109/593] Fixed build system and package.json file filter --- package.json | 3 +-- tasks/concat.js | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 3926657b..c53518d7 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,7 @@ "charting" ], "files": [ - "libdist", - "sitedist", + "dist", "LICENSE", "package.json", "README.md" diff --git a/tasks/concat.js b/tasks/concat.js index e4856946..0c7f2178 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -18,14 +18,14 @@ module.exports = function (grunt) { }, files: { '<%= pkg.config.dist %>/chartist.js': [ - '<%= pkg.config.src %>/core.js', - '<%= pkg.config.src %>/event.js', - '<%= pkg.config.src %>/class.js', - '<%= pkg.config.src %>/base.js', - '<%= pkg.config.src %>/svg.js', - '<%= pkg.config.src %>/charts/line.js', - '<%= pkg.config.src %>/charts/bar.js', - '<%= pkg.config.src %>/charts/pie.js' + '<%= pkg.config.src %>/scripts/core.js', + '<%= pkg.config.src %>/scripts/event.js', + '<%= pkg.config.src %>/scripts/class.js', + '<%= pkg.config.src %>/scripts/base.js', + '<%= pkg.config.src %>/scripts/svg.js', + '<%= pkg.config.src %>/scripts/charts/line.js', + '<%= pkg.config.src %>/scripts/charts/bar.js', + '<%= pkg.config.src %>/scripts/charts/pie.js' ] } } From 493c8eddde4da65b99cb74a4ed884b1d8ee9a266 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 01:19:46 +0100 Subject: [PATCH 110/593] Refactored Chartist.extend to accept var arg sources --- src/scripts/charts/bar.js | 2 +- src/scripts/charts/line.js | 2 +- src/scripts/charts/pie.js | 2 +- src/scripts/core.js | 26 +++++++++++++++----------- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 04525a06..071ec7ba 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -235,7 +235,7 @@ Chartist.Bar.super.constructor.call(this, query, data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), + Chartist.extend({}, defaultOptions, options), responsiveOptions); } diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index aea42aa6..c06e1afe 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -344,7 +344,7 @@ Chartist.Line.super.constructor.call(this, query, data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), + Chartist.extend({}, defaultOptions, options), responsiveOptions); } diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 2edf763d..e474f141 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -277,7 +277,7 @@ Chartist.Pie.super.constructor.call(this, query, data, - Chartist.extend(Chartist.extend({}, defaultOptions), options), + Chartist.extend({}, defaultOptions, options), responsiveOptions); } diff --git a/src/scripts/core.js b/src/scripts/core.js index 0fcc9f89..7a6cc9f2 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -33,24 +33,28 @@ var Chartist = { return String.fromCharCode(97 + n % 26); }; - // TODO: Make it possible to call extend with var args /** * Simple recursive object extend * * @memberof Chartist.Core * @param {Object} target Target object where the source will be merged into - * @param {Object} source This object will be merged into target and then target is returned + * @param {Object...} sources This object (objects) will be merged into target and then target is returned * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source */ - Chartist.extend = function (target, source) { + Chartist.extend = function (target) { target = target || {}; - for (var prop in source) { - if (typeof source[prop] === 'object') { - target[prop] = Chartist.extend(target[prop], source[prop]); - } else { - target[prop] = source[prop]; + + var sources = Array.prototype.slice.call(arguments, 1); + sources.forEach(function(source) { + for (var prop in source) { + if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) { + target[prop] = Chartist.extend(target[prop], source[prop]); + } else { + target[prop] = source[prop]; + } } - } + }); + return target; }; @@ -593,8 +597,8 @@ var Chartist = { * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events * @return {Object} The consolidated options object from the defaults, base and matching responsive options */ - Chartist.optionsProvider = function (defaultOptions, options, responsiveOptions, eventEmitter) { - var baseOptions = Chartist.extend(Chartist.extend({}, defaultOptions), options), + Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) { + var baseOptions = Chartist.extend({}, options), currentOptions, mediaQueryListeners = [], i; From 76b0047282b88843e68c92e995f00c0c1b2af997 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 01:22:10 +0100 Subject: [PATCH 111/593] Added first version of plugin mechansim --- site/code-snippets/plugin-example.js | 24 +++++ site/code-snippets/plugin-include.js | 14 +++ site/code-snippets/plugin-signature.js | 3 + site/data/pages/plugins.yml | 132 +++++++++++++++++++++++++ site/partials/navigation.hbs | 1 + site/templates/plugins.hbs | 9 ++ src/scripts/base.js | 16 ++- src/scripts/core.js | 3 + 8 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 site/code-snippets/plugin-example.js create mode 100644 site/code-snippets/plugin-include.js create mode 100644 site/code-snippets/plugin-signature.js create mode 100644 site/data/pages/plugins.yml create mode 100644 site/templates/plugins.hbs diff --git a/site/code-snippets/plugin-example.js b/site/code-snippets/plugin-example.js new file mode 100644 index 00000000..1eef28b7 --- /dev/null +++ b/site/code-snippets/plugin-example.js @@ -0,0 +1,24 @@ +Chartist.plugins.ctPointLabels = function(chart, options) { + var defaultOptions = { + labelClass: 'ct-label', + labelOffset: { + x: 0, + y: -10 + }, + textAnchor: 'middle' + }; + + options = Chartist.extend({}, defaultOptions, options); + + if(chart instanceof Chartist.Line) { + chart.on('draw', function(data) { + if(data.type === 'point') { + data.group.elem('text', { + x: data.x + options.labelOffset.x, + y: data.y + options.labelOffset.y, + style: 'text-anchor: ' + options.textAnchor + }, options.labelClass).text(data.value); + } + }); + } +}; diff --git a/site/code-snippets/plugin-include.js b/site/code-snippets/plugin-include.js new file mode 100644 index 00000000..36ec5cb8 --- /dev/null +++ b/site/code-snippets/plugin-include.js @@ -0,0 +1,14 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7], + series: [ + [1, 5, 3, 4, 6, 2, 3], + [2, 4, 2, 5, 4, 3, 6] + ] +}, { + plugins: [{ + name: 'chartist-plugin-pointlabels', + options: { + textAnchor: 'middle' + } + }] +}); diff --git a/site/code-snippets/plugin-signature.js b/site/code-snippets/plugin-signature.js new file mode 100644 index 00000000..ccd453c5 --- /dev/null +++ b/site/code-snippets/plugin-signature.js @@ -0,0 +1,3 @@ +function myChartistPlugin(chart, options) { + +} diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml new file mode 100644 index 00000000..1d4d4f25 --- /dev/null +++ b/site/data/pages/plugins.yml @@ -0,0 +1,132 @@ +sections: + - title: Overview + level: 3 + items: + - type: sub-section + data: + title: What's a plugin? + level: 4 + items: + - type: text + data: + text: > + Plugins allow you to extend the basic functionality of your charts. You can develop your own + plugins or use plugins that others have already developed. + + - type: sub-section + data: + title: How to use plugins + level: 4 + items: + - type: text + data: + text: > + Once you have included a plugin in your project it will register itself in the Chartist.js plugin + registry. You can use registered plugins in your chart by specifying them explicitly in the plugins + section of your chart configuration. Check the List of plugins + section to see what plugins you can use. + + - type: code-snippet + data: + id: plugin-include + lang: js + + - type: hint + data: + title: Order of specification + text: > + Plugins are chainable and the order of specification in the plugins array of your configuration + is important for the end result. + + - type: text + data: + text: > + Besides the name of the plugins you would like to use in your chart you can pass an optional + options object to the plugin. Check the individual plugin documentation for a list of valid options. + + - title: Available plugins + level: 3 + items: + - type: text + data: + text: > + Here you can find a list of known plugins. Usually plugins should be available from both Bower and NPM for + installation. If you have developed your own plugin but can't find it here, you should create a + pull request + for this page and add your plugin to the list. + + - type: sub-section + data: + title: List of Plugins + level: 4 + items: + - type: table + data: + id: chartist-plugin-list + header: + - Name and link + rows: + - + - chartist-plugin-pointlabels + + - title: Develop a plugin + level: 3 + items: + - type: text + data: + text: > + Plugins can be registered in this object with their name as property name and a plugin function as + value. Plugin names need to be chosen carefully as they can clash with each other. It's recommended + to use a prefix for plugin names. + + - type: text + data: + text: > + Plugins are functions that will be called for each chart that is created with the plugin enabled + (specified in the plugins configuration of a chart). The plugin function will be called with two + arguments where the first one is the chart that is registering itself for the plugin and the second + argument which is the plugin options specified in the plugins section of the chart configuration. + + - type: code-snippet + data: + id: plugin-signature + lang: js + + - type: text + data: + text: > + From the chart object options, svg (root SVG element) and the + eventEmitter can be used to manipulate the behaviour of the chart. It's the + responsibility of the plugin to decide if it should be activated on a given chart (i.e. by checking + the chart type chart instanceof Chartist.Line etc.). + + - type: text + data: + text: > + It's recommended to use the events of Chartist.js (like draw) to manipulate the + underlying elements. Using the events, plugins can chain up in a natural way and work independently + on extending the functionality of the chart. + + - type: text + data: + text: > + Plugins should contain their own default settings and use Chartist.extend to override + the settings specified in the options passed to the plugin function. Using + the optionsProvider of the chart object one could also implement responsive behaviour. + + - type: sub-section + data: + title: Example Plugin + level: 4 + items: + - type: text + data: + text: > + The following code shows an example plugin that is also available for download and installation. + You can also use the repository + of the example plugin to start your own awesome Chartist.js plugin. + + - type: code-snippet + data: + id: plugin-example + lang: js diff --git a/site/partials/navigation.hbs b/site/partials/navigation.hbs index f6ccea95..3d3f1dc4 100644 --- a/site/partials/navigation.hbs +++ b/site/partials/navigation.hbs @@ -16,6 +16,7 @@
  • Getting started
  • API Documentation
  • Examples (live coding!)
  • +
  • Plugins
  • Contribute
  • diff --git a/site/templates/plugins.hbs b/site/templates/plugins.hbs new file mode 100644 index 00000000..a5a76e3b --- /dev/null +++ b/site/templates/plugins.hbs @@ -0,0 +1,9 @@ +--- +layout: content +page-class: plugins +title: Chartist - Plugins +description: Use plugins to extend the functionality of your charts +--- +{{#each page.sections}} + {{>section}} +{{/each}} diff --git a/src/scripts/base.js b/src/scripts/base.js index 89a6856f..8ccdb974 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -95,8 +95,20 @@ setTimeout(function() { // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes - // TODO: Remove default options parameter from optionsProvider - this.optionsProvider = Chartist.optionsProvider({}, this.options, this.responsiveOptions, this.eventEmitter); + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + + // Before the first chart creation we need to register us with all plugins that are configured + // Initialize all relevant plugins with our chart object and the plugin options specified in the config + if(this.options.plugins) { + this.options.plugins.forEach(function(plugin) { + var pluginFnc = Chartist.plugins[plugin.name]; + if(pluginFnc) { + pluginFnc(this, plugin.options); + } + }.bind(this)); + } + + // Create the first chart this.createChart(this.optionsProvider.currentOptions); }.bind(this), 0); } diff --git a/src/scripts/core.js b/src/scripts/core.js index 7a6cc9f2..cd31f367 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -651,6 +651,9 @@ var Chartist = { }; }; + // Plugin registry for plugin authors to register their plugins + Chartist.plugins = {}; + //http://schepers.cc/getting-to-the-point Chartist.catmullRom2bezier = function (crp, z) { var d = []; From efeabc2f016052e10c6adf7b1cb33091902d0b3f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 01:25:40 +0100 Subject: [PATCH 112/593] Update to 0.4.2 including distribution build files --- CHANGELOG.md | 32 +- bower.json | 2 +- dist/chartist.js | 2607 +++++++++++++++++++++++++++++++++++++- dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- src/scripts/core.js | 2 +- 8 files changed, 2640 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 883f9ad4..fd65fe35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ -v0.4.1 - Tue, 25 Nov 2014 -------------------------- +v0.4.2 - 27 Nov 2014 +-------------------- + +- Included first version of Chartist.js Plugin mechanism +- Major refactoring of development stack (thanks @Autarc !) +- Removed unused functions in Chartist.Core + +v0.4.1 - 21 Nov 2014 +-------------------- + +- Added more functionality to Chartist.Svg: select child elements, parent, root as well as a Svg list wrapper with delegation functions +- Fixed bug in strip unit +- Added classes to the label and grid gorups +- Added this as return value so calls to chart can be chained up easily + + +v0.4.0 - 17 Nov 2014 +-------------------- + +- Added new animation API for SMIL animations +- Added possibility to add event handlers with asterisk that will be triggerd on all events including the event name in the cb function +- Added possibility to pass DOM node to SVG constructor so you can wrap existing SVG nodes into a Chartist.Svg element +- Fixed svg recycling on re-creation +- Fixed resize listener detach that wasn't working properly +- Refactored Chartist.Svg to use Chartist.Class +- Including event when line and area is drawn +- Changed default scaleMinSpace to 20 to be more mobile friendly +- Fixed bug with line area base -- [fe847c8](../../commit/fe847c8) [changed] - organize source files -- [f0cd456](../../commit/f0cd456) [changed] - extract site sources diff --git a/bower.json b/bower.json index 7ab31eb5..e8327848 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.4.1", + "version": "0.4.2", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 55b52de4..2c91a589 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,14 +14,2617 @@ } }(this, function () { - /* Chartist.js 0.4.1 + /* Chartist.js 0.4.2 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ + /** + * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. + * + * @module Chartist.Core + */ + var Chartist = { + version: '0.4.2' + }; + (function (window, document, Chartist) { + 'use strict'; - return Chartist; + /** + * Helps to simplify functional style code + * + * @memberof Chartist.Core + * @param {*} n This exact value will be returned by the noop function + * @return {*} The same value that was provided to the n parameter + */ + Chartist.noop = function (n) { + return n; + }; + + /** + * Generates a-z from a number 0 to 26 + * + * @memberof Chartist.Core + * @param {Number} n A number from 0 to 26 that will result in a letter a-z + * @return {String} A character from a-z based on the input number n + */ + Chartist.alphaNumerate = function (n) { + // Limit to a-z + return String.fromCharCode(97 + n % 26); + }; + + /** + * Simple recursive object extend + * + * @memberof Chartist.Core + * @param {Object} target Target object where the source will be merged into + * @param {Object...} sources This object (objects) will be merged into target and then target is returned + * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source + */ + Chartist.extend = function (target) { + target = target || {}; + + var sources = Array.prototype.slice.call(arguments, 1); + sources.forEach(function(source) { + for (var prop in source) { + if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) { + target[prop] = Chartist.extend(target[prop], source[prop]); + } else { + target[prop] = source[prop]; + } + } + }); + + return target; + }; + + /** + * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {String|Number} value + * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel + */ + Chartist.stripUnit = function(value) { + if(typeof value === 'string') { + value = value.replace(/[^0-9\+-\.]/g, ''); + } + + return +value; + }; + + /** + * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {Number} value + * @param {String} unit + * @returns {String} Returns the passed number value with unit. + */ + Chartist.ensureUnit = function(value, unit) { + if(typeof value === 'number') { + value = value + unit; + } + + return value; + }; + + /** + * This is a wrapper around document.querySelector that will return the query if it's already of type Node + * + * @memberof Chartist.Core + * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly + * @return {Node} + */ + Chartist.querySelector = function(query) { + return query instanceof Node ? query : document.querySelector(query); + }; + + /** + * Create or reinitialize the SVG element for the chart + * + * @memberof Chartist.Core + * @param {Node} container The containing DOM Node object that will be used to plant the SVG element + * @param {String} width Set the width of the SVG element. Default is 100% + * @param {String} height Set the height of the SVG element. Default is 100% + * @param {String} className Specify a class to be added to the SVG element + * @return {Object} The created/reinitialized SVG element + */ + Chartist.createSvg = function (container, width, height, className) { + var svg; + + width = width || '100%'; + height = height || '100%'; + + svg = container.querySelector('svg'); + if(svg) { + container.removeChild(svg); + } + + // Create svg object with width and height or use 100% as default + svg = new Chartist.Svg('svg').attr({ + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); + + // Add the DOM node to our container + container.appendChild(svg._node); + + return svg; + }; + + /** + * Convert data series into plain array + * + * @memberof Chartist.Core + * @param {Object} data The series object that contains the data to be visualized in the chart + * @return {Array} A plain array that contains the data to be visualized in the chart + */ + Chartist.getDataArray = function (data) { + var array = []; + + for (var i = 0; i < data.series.length; i++) { + // If the series array contains an object with a data property we will use the property + // otherwise the value directly (array or number) + array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? + data.series[i].data : data.series[i]; + + // Convert values to number + for (var j = 0; j < array[i].length; j++) { + array[i][j] = +array[i][j]; + } + } + + return array; + }; + + /** + * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart + * + * @memberof Chartist.Core + * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. + * @param {Number} length The length of the x-axis data array. + * @return {Array} The array that got updated with missing values. + */ + Chartist.normalizeDataArray = function (dataArray, length) { + for (var i = 0; i < dataArray.length; i++) { + if (dataArray[i].length === length) { + continue; + } + + for (var j = dataArray[i].length; j < length; j++) { + dataArray[i][j] = 0; + } + } + + return dataArray; + }; + + /** + * Calculate the order of magnitude for the chart scale + * + * @memberof Chartist.Core + * @param {Number} value The value Range of the chart + * @return {Number} The order of magnitude + */ + Chartist.orderOfMagnitude = function (value) { + return Math.floor(Math.log(Math.abs(value)) / Math.LN10); + }; + + /** + * Project a data length into screen coordinates (pixels) + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Number} length Single data value from a series array + * @param {Object} bounds All the values to set the bounds of the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @return {Number} The projected data length in pixels + */ + Chartist.projectLength = function (svg, length, bounds, options) { + var availableHeight = Chartist.getAvailableHeight(svg, options); + return (length / bounds.range * availableHeight); + }; + + /** + * Get the height of the area in the chart for the data series + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @return {Number} The height of the area in the chart for the data series + */ + Chartist.getAvailableHeight = function (svg, options) { + return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); + }; + + /** + * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. + * + * @memberof Chartist.Core + * @param {Array} dataArray The array that contains the data to be visualized in the chart + * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart. + */ + Chartist.getHighLow = function (dataArray) { + var i, + j, + highLow = { + high: -Number.MAX_VALUE, + low: Number.MAX_VALUE + }; + + for (i = 0; i < dataArray.length; i++) { + for (j = 0; j < dataArray[i].length; j++) { + if (dataArray[i][j] > highLow.high) { + highLow.high = dataArray[i][j]; + } + + if (dataArray[i][j] < highLow.low) { + highLow.low = dataArray[i][j]; + } + } + } + + return highLow; + }; + + // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude + /** + * Calculate and retrieve all the bounds for the chart and return them in one array + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Array} normalizedData The array that got updated with missing values. + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} referenceValue The reference value for the chart. + * @return {Object} All the values to set the bounds of the chart + */ + Chartist.getBounds = function (svg, normalizedData, options, referenceValue) { + var i, + newMin, + newMax, + bounds = Chartist.getHighLow(normalizedData); + + // Overrides of high / low from settings + bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); + bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); + + // If high and low are the same because of misconfiguration or flat data (only the same value) we need + // to set the high or low to 0 depending on the polarity + if(bounds.high === bounds.low) { + // If both values are 0 we set high to 1 + if(bounds.low === 0) { + bounds.high = 1; + } else if(bounds.low < 0) { + // If we have the same negative value for the bounds we set bounds.high to 0 + bounds.high = 0; + } else { + // If we have the same positive value for the bounds we set bounds.low to 0 + bounds.low = 0; + } + } + + // Overrides of high / low based on reference value, it will make sure that the invisible reference value is + // used to generate the chart. This is useful when the chart always needs to contain the position of the + // invisible reference value in the view i.e. for bipolar scales. + if (referenceValue || referenceValue === 0) { + bounds.high = Math.max(referenceValue, bounds.high); + bounds.low = Math.min(referenceValue, bounds.low); + } + + bounds.valueRange = bounds.high - bounds.low; + bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); + bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); + bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); + bounds.range = bounds.max - bounds.min; + bounds.step = Math.pow(10, bounds.oom); + bounds.numberOfSteps = Math.round(bounds.range / bounds.step); + + // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace + // If we are already below the scaleMinSpace value we will scale up + var length = Chartist.projectLength(svg, bounds.step, bounds, options), + scaleUp = length < options.axisY.scaleMinSpace; + + while (true) { + if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { + bounds.step /= 2; + } else { + break; + } + } + + // Narrow min and max based on new step + newMin = bounds.min; + newMax = bounds.max; + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + if (i + bounds.step < bounds.low) { + newMin += bounds.step; + } + + if (i - bounds.step >= bounds.high) { + newMax -= bounds.step; + } + } + bounds.min = newMin; + bounds.max = newMax; + bounds.range = bounds.max - bounds.min; + + bounds.values = []; + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + bounds.values.push(i); + } + + return bounds; + }; + + /** + * Calculate cartesian coordinates of polar coordinates + * + * @memberof Chartist.Core + * @param {Number} centerX X-axis coordinates of center point of circle segment + * @param {Number} centerY X-axis coordinates of center point of circle segment + * @param {Number} radius Radius of circle segment + * @param {Number} angleInDegrees Angle of circle segment in degrees + * @return {Number} Coordinates of point on circumference + */ + Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { + var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; + + return { + x: centerX + (radius * Math.cos(angleInRadians)), + y: centerY + (radius * Math.sin(angleInRadians)) + }; + }; + + /** + * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements + */ + Chartist.createChartRect = function (svg, options) { + var yOffset = options.axisY ? options.axisY.offset : 0, + xOffset = options.axisX ? options.axisX.offset : 0; + + return { + x1: options.chartPadding + yOffset, + y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), + y2: options.chartPadding, + width: function () { + return this.x2 - this.x1; + }, + height: function () { + return this.y1 - this.y2; + } + }; + }; + + /** + * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. + * + * @param {Object} parent The SVG element where the label should be created as a child + * @param {String} text The label text + * @param {Object} attributes An object with all attributes that should be set on the label element + * @param {String} className The class names that should be set for this element + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + * @returns {Object} The newly created SVG element + */ + Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { + if(supportsForeignObject) { + var content = '' + text + ''; + return parent.foreignObject(content, attributes); + } else { + return parent.elem('text', attributes, className).text(text); + } + }; + + /** + * Generate grid lines and labels for the x-axis into grid and labels group SVG elements + * + * @memberof Chartist.Core + * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element + * @param {Object} data The Object that contains the data to be visualized in the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + */ + Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { + // Create X-Axis + data.labels.forEach(function (value, index) { + var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), + width = chartRect.width() / data.labels.length, + height = options.axisX.offset, + pos = chartRect.x1 + width * index; + + // If interpolated value returns falsey (except 0) we don't draw the grid line + if (!interpolatedValue && interpolatedValue !== 0) { + return; + } + + if (options.axisX.showGrid) { + var gridElement = grid.elem('line', { + x1: pos, + y1: chartRect.y1, + x2: pos, + y2: chartRect.y2 + }, [options.classNames.grid, options.classNames.horizontal].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'x', + index: index, + group: grid, + element: gridElement, + x1: pos, + y1: chartRect.y1, + x2: pos, + y2: chartRect.y2 + }); + } + + if (options.axisX.showLabel) { + var labelPosition = { + x: pos + options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) + }; + + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'x', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.width; + } + }); + } + }); + }; + + /** + * Generate grid lines and labels for the y-axis into grid and labels group SVG elements + * + * @memberof Chartist.Core + * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element + * @param {Object} bounds All the values to set the bounds of the chart + * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart + * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines + * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element + */ + Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { + // Create Y-Axis + bounds.values.forEach(function (value, index) { + var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), + width = options.axisY.offset, + height = chartRect.height() / bounds.values.length, + pos = chartRect.y1 - height * index; + + // If interpolated value returns falsey (except 0) we don't draw the grid line + if (!interpolatedValue && interpolatedValue !== 0) { + return; + } + + if (options.axisY.showGrid) { + var gridElement = grid.elem('line', { + x1: chartRect.x1, + y1: pos, + x2: chartRect.x2, + y2: pos + }, [options.classNames.grid, options.classNames.vertical].join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', { + type: 'grid', + axis: 'y', + index: index, + group: grid, + element: gridElement, + x1: chartRect.x1, + y1: pos, + x2: chartRect.x2, + y2: pos + }); + } + + if (options.axisY.showLabel) { + var labelPosition = { + x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), + y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) + }; + + var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + style: 'overflow: visible;' + }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); + + eventEmitter.emit('draw', { + type: 'label', + axis: 'y', + index: index, + group: labels, + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y, + width: width, + height: height, + // TODO: Remove in next major release + get space() { + window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); + return this.height; + } + }); + } + }); + }; + + /** + * Determine the current point on the svg element to draw the data series + * + * @memberof Chartist.Core + * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element + * @param {Object} bounds All the values to set the bounds of the chart + * @param {Array} data The array that contains the data to be visualized in the chart + * @param {Number} index The index of the current project point + * @return {Object} The coordinates object of the current project point containing an x and y number property + */ + Chartist.projectPoint = function (chartRect, bounds, data, index) { + return { + x: chartRect.x1 + chartRect.width() / data.length * index, + y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) + }; + }; + + // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one + /** + * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches + * + * @memberof Chartist.Core + * @param {Object} defaultOptions Default options from Chartist + * @param {Object} options Options set by user + * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart + * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events + * @return {Object} The consolidated options object from the defaults, base and matching responsive options + */ + Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) { + var baseOptions = Chartist.extend({}, options), + currentOptions, + mediaQueryListeners = [], + i; + + function updateCurrentOptions() { + var previousOptions = currentOptions; + currentOptions = Chartist.extend({}, baseOptions); + + if (responsiveOptions) { + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + if (mql.matches) { + currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]); + } + } + } + + if(eventEmitter) { + eventEmitter.emit('optionsChanged', { + previousOptions: previousOptions, + currentOptions: currentOptions + }); + } + } + + function removeMediaQueryListeners() { + mediaQueryListeners.forEach(function(mql) { + mql.removeListener(updateCurrentOptions); + }); + } + + if (!window.matchMedia) { + throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; + } else if (responsiveOptions) { + + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + mql.addListener(updateCurrentOptions); + mediaQueryListeners.push(mql); + } + } + // Execute initially so we get the correct options + updateCurrentOptions(); + + return { + get currentOptions() { + return Chartist.extend({}, currentOptions); + }, + removeMediaQueryListeners: removeMediaQueryListeners + }; + }; + + // Plugin registry for plugin authors to register their plugins + Chartist.plugins = {}; + + //http://schepers.cc/getting-to-the-point + Chartist.catmullRom2bezier = function (crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 === i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 === i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push( + [ + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6 * p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ] + ); + } + + return d; + }; + + }(window, document, Chartist)); + ;/** + * A very basic event module that helps to generate and catch events. + * + * @module Chartist.Event + */ + /* global Chartist */ + (function (window, document, Chartist) { + 'use strict'; + + Chartist.EventEmitter = function () { + var handlers = []; + + /** + * Add an event handler for a specific event + * + * @memberof Chartist.Event + * @param {String} event The event name + * @param {Function} handler A event handler function + */ + function addEventHandler(event, handler) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + } + + /** + * Remove an event handler of a specific event name or remove all event handlers for a specific event. + * + * @memberof Chartist.Event + * @param {String} event The event name where a specific or all handlers should be removed + * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. + */ + function removeEventHandler(event, handler) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + // If handler is set we will look for a specific handler and only remove this + if(handler) { + handlers[event].splice(handlers[event].indexOf(handler), 1); + if(handlers[event].length === 0) { + delete handlers[event]; + } + } else { + // If no handler is specified we remove all handlers for this event + delete handlers[event]; + } + } + } + + /** + * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. + * + * @memberof Chartist.Event + * @param {String} event The event name that should be triggered + * @param {*} data Arbitrary data that will be passed to the event handler callback functions + */ + function emit(event, data) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + handlers[event].forEach(function(handler) { + handler(data); + }); + } + + // Emit event to star event handlers + if(handlers['*']) { + handlers['*'].forEach(function(starHandler) { + starHandler(event, data); + }); + } + } + + return { + addEventHandler: addEventHandler, + removeEventHandler: removeEventHandler, + emit: emit + }; + }; + + }(window, document, Chartist)); + ;/** + * This module provides some basic prototype inheritance utilities. + * + * @module Chartist.Class + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + function listToArray(list) { + var arr = []; + if (list.length) { + for (var i = 0; i < list.length; i++) { + arr.push(list[i]); + } + } + return arr; + } + + /** + * Method to extend from current prototype. + * + * @memberof Chartist.Class + * @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. + * @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. + * @returns {Function} Constructor function of the new class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + */ + function extend(properties, superProtoOverride) { + var superProto = superProtoOverride || this.prototype || Chartist.Class; + var proto = Object.create(superProto); + + Chartist.Class.cloneDefinitions(proto, properties); + + var constr = function() { + var fn = proto.constructor || function () {}, + instance; + + // If this is linked to the Chartist namespace the constructor was not called with new + // To provide a fallback we will instantiate here and return the instance + instance = this === Chartist ? Object.create(proto) : this; + fn.apply(instance, Array.prototype.slice.call(arguments, 0)); + + // If this constructor was not called with new we need to return the instance + // This will not harm when the constructor has been called with new as the returned value is ignored + return instance; + }; + + constr.prototype = proto; + constr.super = superProto; + constr.extend = this.extend; + + return constr; + } + + /** + * Creates a mixin from multiple super prototypes. + * + * @memberof Chartist.Class + * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. + * @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. + * @returns {Function} Constructor function of the newly created mixin class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, + * + * eat: function() { + * this.sugar = 0; + * return this; + * } + * }); + * + * var Banana = Fruit.extend({ + * length: undefined, + * + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * + * var KCal = Class.extend({ + * sugar: 0, + * + * constructor: function(sugar) { + * this.sugar = sugar; + * }, + * + * get kcal() { + * return [this.sugar * 4, 'kcal'].join(''); + * } + * }); + * + * var Nameable = Class.extend({ + * name: undefined, + * + * constructor: function(name) { + * this.name = name; + * } + * }); + * + * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { + * constructor: function(name, length, sugar) { + * Nameable.prototype.constructor.call(this, name); + * Banana.prototype.constructor.call(this, length, sugar); + * }, + * + * toString: function() { + * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); + * } + * }); + * + * + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + * + * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); + * console.log(superBanana.toString()); + * + */ + function mix(mixProtoArr, properties) { + if(this !== Chartist.Class) { + throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); + } + + // Make sure our mixin prototypes are the class objects and not the constructors + var superPrototypes = [{}] + .concat(mixProtoArr) + .map(function (prototype) { + return prototype instanceof Function ? prototype.prototype : prototype; + }); + + var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); + // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype + delete mixedSuperProto.constructor; + return this.extend(properties, mixedSuperProto); + } + + // Variable argument list clones args > 0 into args[0] and retruns modified args[0] + function cloneDefinitions() { + var args = listToArray(arguments); + var target = args[0]; + + args.splice(1, args.length - 1).forEach(function (source) { + Object.getOwnPropertyNames(source).forEach(function (propName) { + // If this property already exist in target we delete it first + delete target[propName]; + // Define the property with the descriptor from source + Object.defineProperty(target, propName, + Object.getOwnPropertyDescriptor(source, propName)); + }); + }); + + return target; + } + + Chartist.Class = { + extend: extend, + mix: mix, + cloneDefinitions: cloneDefinitions + }; + + }(window, document, Chartist)); + ;/** + * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. + * + * @module Chartist.Base + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container + /** + * Updates the chart which currently does a full reconstruction of the SVG DOM + * + * @memberof Chartist.Base + */ + function update() { + this.createChart(this.optionsProvider.currentOptions); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + */ + function detach() { + window.removeEventListener('resize', this.resizeListener); + this.optionsProvider.removeMediaQueryListeners(); + return this; + } + + /** + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. + * + * @memberof Chartist.Base + * @param {String} event Name of the event. Check the examples for supported events. + * @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. + */ + function on(event, handler) { + this.eventEmitter.addEventHandler(event, handler); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + * @param {String} event Name of the event for which a handler should be removed + * @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. + */ + function off(event, handler) { + this.eventEmitter.removeEventHandler(event, handler); + return this; + } + + /** + * Constructor of chart base class. + * + * @param query + * @param data + * @param options + * @param responsiveOptions + * @constructor + */ + function Base(query, data, options, responsiveOptions) { + this.container = Chartist.querySelector(query); + this.data = data; + this.options = options; + this.responsiveOptions = responsiveOptions; + this.eventEmitter = Chartist.EventEmitter(); + this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); + this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); + this.resizeListener = function resizeListener(){ + this.update(); + }.bind(this); + + if(this.container) { + // If chartist was already initialized in this container we are detaching all event listeners first + if(this.container.__chartist__) { + this.container.__chartist__.detach(); + } + + this.container.__chartist__ = this; + } + + window.addEventListener('resize', this.resizeListener); + + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + setTimeout(function() { + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + + // Before the first chart creation we need to register us with all plugins that are configured + // Initialize all relevant plugins with our chart object and the plugin options specified in the config + if(this.options.plugins) { + this.options.plugins.forEach(function(plugin) { + var pluginFnc = Chartist.plugins[plugin.name]; + if(pluginFnc) { + pluginFnc(this, plugin.options); + } + }.bind(this)); + } + + // Create the first chart + this.createChart(this.optionsProvider.currentOptions); + }.bind(this), 0); + } + + // Creating the chart base class + Chartist.Base = Chartist.Class.extend({ + constructor: Base, + optionsProvider: undefined, + container: undefined, + svg: undefined, + eventEmitter: undefined, + createChart: function() { + throw new Error('Base chart type can\'t be instantiated!'); + }, + update: update, + detach: detach, + on: on, + off: off, + version: Chartist.version, + supportsForeignObject: false + }); + + }(window, document, Chartist)); + ;/** + * Chartist SVG module for simple SVG DOM abstraction + * + * @module Chartist.Svg + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + var svgNs = 'http://www.w3.org/2000/svg', + xmlNs = 'http://www.w3.org/2000/xmlns/', + xhtmlNs = 'http://www.w3.org/1999/xhtml'; + + Chartist.xmlNs = { + qualifiedName: 'xmlns:ct', + prefix: 'ct', + uri: 'http://gionkunz.github.com/chartist-js/ct' + }; + + /** + * 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. + * + * @memberof Chartist.Svg + * @constructor + * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg + * @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. + * @param {String} className This class or class list will be added to the SVG element + * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child + * @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 + */ + function Svg(name, attributes, className, parent, insertFirst) { + // If Svg is getting called with an SVG element we just return the wrapper + if(name instanceof SVGElement) { + this._node = name; + } else { + this._node = document.createElementNS(svgNs, name); + + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + } + + if(attributes) { + this.attr(attributes); + } + + if(className) { + this.addClass(className); + } + + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); + } + } + } + } + + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Chartist.Svg + * @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. + * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @returns {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. + */ + function attr(attributes, ns) { + if(typeof attributes === 'string') { + if(ns) { + return this._node.getAttributeNS(ns, attributes); + } else { + return this._node.getAttribute(attributes); + } + } + + Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; + } + + if(ns) { + this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + } else { + this._node.setAttribute(key, attributes[key]); + } + }.bind(this)); + + return this; + } + + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + function elem(name, attributes, className, insertFirst) { + return new Chartist.Svg(name, attributes, className, this, insertFirst); + } + + /** + * Returns the parent Chartist.SVG wrapper object + * + * @returns {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. + */ + function parent() { + return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; + } + + /** + * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. + * + * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element + */ + function root() { + var node = this._node; + while(node.nodeName !== 'svg') { + node = node.parentNode; + } + return new Chartist.Svg(node); + } + + /** + * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found + */ + function querySelector(selector) { + var foundNode = this._node.querySelector(selector); + return foundNode ? new Chartist.Svg(foundNode) : null; + } + /** + * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found + */ + function querySelectorAll(selector) { + var foundNodes = this._node.querySelectorAll(selector); + return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; + } + + /** + * 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. + * + * @memberof Chartist.Svg + * @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 + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element + */ + function foreignObject(content, attributes, className, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; + } + + // Adding namespace to content element + content.setAttribute('xmlns', xhtmlNs); + + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = this.elem('foreignObject', attributes, className, insertFirst); + + // Add content to foreignObjectElement + fnObj._node.appendChild(content); + + return fnObj; + } + + /** + * This method adds a new text element to the current Chartist.Svg wrapper. + * + * @memberof Chartist.Svg + * @param {String} t The text that should be added to the text element that is created + * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element + */ + function text(t) { + this._node.appendChild(document.createTextNode(t)); + return this; + } + + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Chartist.Svg + * @returns {Chartist.Svg} The same wrapper object that got emptied + */ + function empty() { + while (this._node.firstChild) { + this._node.removeChild(this._node.firstChild); + } + + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg + * @returns {Chartist.Svg} The parent wrapper object of the element that got removed + */ + function remove() { + this._node.parentNode.removeChild(this._node); + return new Chartist.Svg(this._node.parentNode); + } + + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Chartist.Svg + * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object + * @returns {Chartist.Svg} The wrapper of the new element + */ + function replace(newElement) { + this._node.parentNode.replaceChild(newElement._node, this._node); + return newElement; + } + + /** + * This method will append an element to the current element as a child. + * + * @memberof Chartist.Svg + * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @returns {Chartist.Svg} The wrapper of the appended object + */ + function append(element, insertFirst) { + if(insertFirst && this._node.firstChild) { + this._node.insertBefore(element._node, this._node.firstChild); + } else { + this._node.appendChild(element._node); + } + + return this; + } + + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Chartist.Svg + * @returns {Array} A list of classes or an empty array if there are no classes on the current element + */ + function classes() { + return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; + } + + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Chartist.Svg} The wrapper of the current element + */ + function addClass(names) { + this._node.setAttribute('class', + this.classes(this._node) + .concat(names.trim().split(/\s+/)) + .filter(function(elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ') + ); + + return this; + } + + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @returns {Chartist.Svg} The wrapper of the current element + */ + function removeClass(names) { + var removedClasses = names.trim().split(/\s+/); + + this._node.setAttribute('class', this.classes(this._node).filter(function(name) { + return removedClasses.indexOf(name) === -1; + }).join(' ')); + + return this; + } + + /** + * Removes all classes from the current element. + * + * @memberof Chartist.Svg + * @returns {Chartist.Svg} The wrapper of the current element + */ + function removeAllClasses() { + this._node.setAttribute('class', ''); + + return this; + } + + /** + * Get element height with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Svg + * @return {Number} The elements height in pixels + */ + function height() { + return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; + } + + /** + * Get element width with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + function width() { + return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + } + + /** + * 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. + * **An animations object could look like this:** + * ```javascript + * element.animate({ + * opacity: { + * dur: 1000, + * from: 0, + * to: 1 + * }, + * x1: { + * dur: '1000ms', + * from: 100, + * to: 200, + * easing: 'easeOutQuart' + * }, + * y1: { + * dur: '2s', + * from: 0, + * to: 100 + * } + * }); + * ``` + * **Automatic unit conversion** + * 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. + * **Guided mode** + * 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. + * If guided mode is enabled the following behavior is added: + * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) + * - The animate element will be forced to use `fill="freeze"` + * - 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. + * - After the animation the element attribute value will be set to the `to` value of the animation + * - The animate element is deleted from the DOM + * + * @memberof Chartist.Svg + * @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. + * @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. + * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. + * @returns {Chartist.Svg} The current element where the animation was added + */ + function animate(animations, guided, eventEmitter) { + if(guided === undefined) { + guided = true; + } + + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + + function createAnimate(animationDefinition, guided) { + var attributeProperties = {}, + animate, + timeout, + easing; + + // Check if an easing is specified in the definition object and delete it from the object as it will not + // be part of the animate element attributes. + if(animationDefinition.easing) { + // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object + easing = animationDefinition.easing instanceof Array ? + animationDefinition.easing : + Chartist.Svg.Easing[animationDefinition.easing]; + delete animationDefinition.easing; + } + + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); + + if(easing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = easing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + + // Adding "fill: freeze" if we are in guided mode and set initial attribute values + if(guided) { + animationDefinition.fill = 'freeze'; + // Animated property on our element should already be set to the animation from value in guided mode + attributeProperties[attribute] = animationDefinition.from; + this.attr(attributeProperties); + + // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin + // which needs to be in ms aside + timeout = Chartist.stripUnit(animationDefinition.begin || 0); + animationDefinition.begin = 'indefinite'; + } + + animate = this.elem('animate', Chartist.extend({ + attributeName: attribute + }, animationDefinition)); + + if(guided) { + // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout + setTimeout(function() { + animate._node.beginElement(); + }, timeout); + } + + if(eventEmitter) { + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animationDefinition + }); + }.bind(this)); + } + + animate._node.addEventListener('endEvent', function handleEndEvent() { + if(eventEmitter) { + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animationDefinition + }); + } + + if(guided) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this)); + } + + // If current attribute is an array of definition objects we create an animate for each and disable guided mode + if(animations[attribute] instanceof Array) { + animations[attribute].forEach(function(animationDefinition) { + createAnimate.bind(this)(animationDefinition, false); + }.bind(this)); + } else { + createAnimate.bind(this)(animations[attribute], guided); + } + + }.bind(this)); + + return this; + } + + Chartist.Svg = Chartist.Class.extend({ + constructor: Svg, + attr: attr, + elem: elem, + parent: parent, + root: root, + querySelector: querySelector, + querySelectorAll: querySelectorAll, + foreignObject: foreignObject, + text: text, + empty: empty, + remove: remove, + replace: replace, + append: append, + classes: classes, + addClass: addClass, + removeClass: removeClass, + removeAllClasses: removeAllClasses, + height: height, + width: width, + animate: animate + }); + + /** + * 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. + * + * @memberof Chartist.Svg + * @param {String} feature The SVG 1.1 feature that should be checked for support. + * @returns {Boolean} True of false if the feature is supported or not + */ + Chartist.Svg.isSupported = function(feature) { + return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); + }; + + /** + * 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. + * + * @memberof Chartist.Svg + */ + var easingCubicBeziers = { + easeInSine: [0.47, 0, 0.745, 0.715], + easeOutSine: [0.39, 0.575, 0.565, 1], + easeInOutSine: [0.445, 0.05, 0.55, 0.95], + easeInQuad: [0.55, 0.085, 0.68, 0.53], + easeOutQuad: [0.25, 0.46, 0.45, 0.94], + easeInOutQuad: [0.455, 0.03, 0.515, 0.955], + easeInCubic: [0.55, 0.055, 0.675, 0.19], + easeOutCubic: [0.215, 0.61, 0.355, 1], + easeInOutCubic: [0.645, 0.045, 0.355, 1], + easeInQuart: [0.895, 0.03, 0.685, 0.22], + easeOutQuart: [0.165, 0.84, 0.44, 1], + easeInOutQuart: [0.77, 0, 0.175, 1], + easeInQuint: [0.755, 0.05, 0.855, 0.06], + easeOutQuint: [0.23, 1, 0.32, 1], + easeInOutQuint: [0.86, 0, 0.07, 1], + easeInExpo: [0.95, 0.05, 0.795, 0.035], + easeOutExpo: [0.19, 1, 0.22, 1], + easeInOutExpo: [1, 0, 0, 1], + easeInCirc: [0.6, 0.04, 0.98, 0.335], + easeOutCirc: [0.075, 0.82, 0.165, 1], + easeInOutCirc: [0.785, 0.135, 0.15, 0.86], + easeInBack: [0.6, -0.28, 0.735, 0.045], + easeOutBack: [0.175, 0.885, 0.32, 1.275], + easeInOutBack: [0.68, -0.55, 0.265, 1.55] + }; + + Chartist.Svg.Easing = easingCubicBeziers; + + /** + * 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. + * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. + * + * @memberof Chartist.Svg + * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) + * @constructor + */ + function SvgList(nodeList) { + var list = this; + + this.svgElements = []; + for(var i = 0; i < nodeList.length; i++) { + this.svgElements.push(new Chartist.Svg(nodeList[i])); + } + + // Add delegation methods for Chartist.Svg + Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { + return ['constructor', + 'parent', + 'querySelector', + 'querySelectorAll', + 'replace', + 'append', + 'classes', + 'height', + 'width'].indexOf(prototypeProperty) === -1; + }).forEach(function(prototypeProperty) { + list[prototypeProperty] = function() { + var args = Array.prototype.slice.call(arguments, 0); + list.svgElements.forEach(function(element) { + Chartist.Svg.prototype[prototypeProperty].apply(element, args); + }); + return list; + }; + }); + } + + Chartist.Svg.List = Chartist.Class.extend({ + constructor: SvgList + }); + + }(window, document, Chartist)); + ;/** + * 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. + * + * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. + * + * @module Chartist.Line + */ + /* global Chartist */ + (function(window, document, Chartist){ + 'use strict'; + + var defaultOptions = { + axisX: { + offset: 30, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 40, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 20 + }, + width: undefined, + height: undefined, + showLine: true, + showPoint: true, + showArea: false, + areaBase: 0, + lineSmooth: true, + low: undefined, + high: undefined, + chartPadding: 5, + 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', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg object + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options); + + var chartRect = Chartist.createChartRect(this.svg, options); + // Start drawing + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var p, + pathCoordinates = [], + point; + + for (var j = 0; j < normalizedData[i].length; j++) { + p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); + pathCoordinates.push(p.x, p.y); + + //If we should show points we need to create them now to avoid secondary loop + // Small offset for Firefox to render squares correctly + if (options.showPoint) { + point = seriesGroups[i].elem('line', { + x1: p.x, + y1: p.y, + x2: p.x + 0.01, + y2: p.y + }, options.classNames.point).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'point', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: point, + x: p.x, + y: p.y + }); + } + } + + // TODO: Nicer handling of conditions, maybe composition? + if (options.showLine || options.showArea) { + // TODO: We should add a path API in the SVG library for easier path creation + var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; + + // If smoothed path and path has more than two points then use catmull rom to bezier algorithm + if (options.lineSmooth && pathCoordinates.length > 4) { + + var cr = Chartist.catmullRom2bezier(pathCoordinates); + for(var k = 0; k < cr.length; k++) { + pathElements.push('C' + cr[k].join()); + } + } else { + for(var l = 3; l < pathCoordinates.length; l += 2) { + pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); + } + } + + if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); + + // If we need to draw area shapes we just make a copy of our pathElements SVG path array + var areaPathElements = pathElements.slice(); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); + // And splice our new area path array to add the missing path elements to close the area shape + areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); + areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; + areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + + // Create the new path for the area shape with the area class from the options + var area = seriesGroups[i].elem('path', { + d: areaPathElements.join('') + }, options.classNames.area, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: area + }); + } + + if(options.showLine) { + var line = seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: line + }); + } + } + } + + this.eventEmitter.emit('created', { + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options + }); + } + + /** + * This method creates a new line chart. + * + * @memberof Chartist.Line + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // These are the default options of the line chart + * var options = { + * // Options for X-Axis + * axisX: { + * // The offset of the labels to the chart area + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;} + * }, + * // Options for Y-Axis + * axisY: { + * // The offset of the labels to the chart area + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;}, + * // This value specifies the minimum height in pixel of the scale steps + * scaleMinSpace: 30 + * }, + * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + * width: undefined, + * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + * height: undefined, + * // If the line should be drawn or not + * showLine: true, + * // If dots should be drawn or not + * showPoint: true, + * // If the line chart should draw an area + * showArea: false, + * // The base for the area chart that will be used to close the area shape (is normally 0) + * areaBase: 0, + * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) + * lineSmooth: true, + * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + * low: undefined, + * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + * high: undefined, + * // Padding of the chart drawing area to the container element and labels + * chartPadding: 5, + * // Override the class names that get used to generate the SVG structure of the chart + * 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', + * vertical: 'ct-vertical', + * horizontal: 'ct-horizontal' + * } + * }; + * + * @example + * // Create a simple line chart + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // As options we currently only set a static size of 300x200 px + * var options = { + * width: '300px', + * height: '200px' + * }; + * + * // 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 + * new Chartist.Line('.ct-chart', data, options); + * + * @example + * // Create a line chart with responsive options + * + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. + * var responsiveOptions = [ + * ['screen and (min-width: 641px) and (max-width: 1024px)', { + * showPoint: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return Mon, Tue, Wed etc. on medium screens + * return value.slice(0, 3); + * } + * } + * }], + * ['screen and (max-width: 640px)', { + * showLine: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return M, T, W etc. on small screens + * return value[0]; + * } + * } + * }] + * ]; + * + * new Chartist.Line('.ct-chart', data, null, responsiveOptions); + * + */ + function Line(query, data, options, responsiveOptions) { + Chartist.Line.super.constructor.call(this, + query, + data, + Chartist.extend({}, defaultOptions, options), + responsiveOptions); + } + + // Creating line chart type in Chartist namespace + Chartist.Line = Chartist.Base.extend({ + constructor: Line, + createChart: createChart + }); + + }(window, document, Chartist)); + ;/** + * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. + * + * @module Chartist.Bar + */ + /* global Chartist */ + (function(window, document, Chartist){ + 'use strict'; + + var defaultOptions = { + axisX: { + offset: 30, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 40, + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true, + labelInterpolationFnc: Chartist.noop, + scaleMinSpace: 20 + }, + width: undefined, + height: undefined, + high: undefined, + low: undefined, + chartPadding: 5, + seriesBarDistance: 15, + classNames: { + chart: 'ct-chart-bar', + label: 'ct-label', + labelGroup: 'ct-labels', + series: 'ct-series', + bar: 'ct-bar', + grid: 'ct-grid', + gridGroup: 'ct-grids', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; + + function createChart(options) { + var seriesGroups = [], + bounds, + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + + // Create new svg element + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + // initialize bounds + bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); + + var chartRect = Chartist.createChartRect(this.svg, options); + // Start drawing + var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), + grid = this.svg.elem('g').addClass(options.classNames.gridGroup), + // Projected 0 point + zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); + + Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. + var biPol = i - (this.data.series.length - 1) / 2, + // Half of the period with between vertical grid lines used to position bars + periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; + + seriesGroups[i] = this.svg.elem('g'); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + for(var j = 0; j < normalizedData[i].length; j++) { + var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), + bar; + + // Offset to center bar between grid lines and using bi-polar offset for multiple series + // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors + p.x += periodHalfWidth + (biPol * options.seriesBarDistance); + + bar = seriesGroups[i].elem('line', { + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }, options.classNames.bar).attr({ + 'value': normalizedData[i][j] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'bar', + value: normalizedData[i][j], + index: j, + group: seriesGroups[i], + element: bar, + x1: p.x, + y1: zeroPoint.y, + x2: p.x, + y2: p.y + }); + } + } + + this.eventEmitter.emit('created', { + bounds: bounds, + chartRect: chartRect, + svg: this.svg, + options: options + }); + } + + /** + * This method creates a new bar chart and returns API object that you can use for later changes. + * + * @memberof Chartist.Bar + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // These are the default options of the bar chart + * var options = { + * // Options for X-Axis + * axisX: { + * // The offset of the chart drawing area to the border of the container + * offset: 30, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;} + * }, + * // Options for Y-Axis + * axisY: { + * // The offset of the chart drawing area to the border of the container + * offset: 40, + * // Allows you to correct label positioning on this axis by positive or negative x and y offset. + * labelOffset: { + * x: 0, + * y: 0 + * }, + * // If labels should be shown or not + * showLabel: true, + * // If the axis grid should be drawn or not + * showGrid: true, + * // Interpolation function that allows you to intercept the value from the axis label + * labelInterpolationFnc: function(value){return value;}, + * // This value specifies the minimum height in pixel of the scale steps + * scaleMinSpace: 30 + * }, + * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + * width: undefined, + * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + * height: undefined, + * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + * low: undefined, + * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + * high: undefined, + * // Padding of the chart drawing area to the container element and labels + * chartPadding: 5, + * // Specify the distance in pixel of bars in a group + * seriesBarDistance: 15, + * // Override the class names that get used to generate the SVG structure of the chart + * classNames: { + * chart: 'ct-chart-bar', + * label: 'ct-label', + * labelGroup: 'ct-labels', + * series: 'ct-series', + * bar: 'ct-bar', + * grid: 'ct-grid', + * gridGroup: 'ct-grids', + * vertical: 'ct-vertical', + * horizontal: 'ct-horizontal' + * } + * }; + * + * @example + * // Create a simple bar chart + * var data = { + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // 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. + * new Chartist.Bar('.ct-chart', data); + * + * @example + * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 + * new Chartist.Bar('.ct-chart', { + * labels: [1, 2, 3, 4, 5, 6, 7], + * series: [ + * [1, 3, 2, -5, -3, 1, -6], + * [-5, -2, -4, -1, 2, -3, 1] + * ] + * }, { + * seriesBarDistance: 12, + * low: -10, + * high: 10 + * }); + * + */ + function Bar(query, data, options, responsiveOptions) { + Chartist.Bar.super.constructor.call(this, + query, + data, + Chartist.extend({}, defaultOptions, options), + responsiveOptions); + } + + // Creating bar chart type in Chartist namespace + Chartist.Bar = Chartist.Base.extend({ + constructor: Bar, + createChart: createChart + }); + + }(window, document, Chartist)); + ;/** + * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts + * + * @module Chartist.Pie + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + var defaultOptions = { + width: undefined, + height: undefined, + chartPadding: 5, + classNames: { + chart: 'ct-chart-pie', + series: 'ct-series', + slice: 'ct-slice', + donut: 'ct-donut', + label: 'ct-label' + }, + startAngle: 0, + total: undefined, + donut: false, + donutWidth: 60, + showLabel: true, + labelOffset: 0, + labelInterpolationFnc: Chartist.noop, + labelOverflow: false, + labelDirection: 'neutral' + }; + + function determineAnchorPosition(center, label, direction) { + var toTheRight = label.x > center.x; + + if(toTheRight && direction === 'explode' || + !toTheRight && direction === 'implode') { + return 'start'; + } else if(toTheRight && direction === 'implode' || + !toTheRight && direction === 'explode') { + return 'end'; + } else { + return 'middle'; + } + } + + function createChart(options) { + var seriesGroups = [], + chartRect, + radius, + labelRadius, + totalDataSum, + startAngle = options.startAngle, + dataArray = Chartist.getDataArray(this.data); + + // Create SVG.js draw + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + // Calculate charting rect + chartRect = Chartist.createChartRect(this.svg, options, 0, 0); + // Get biggest circle radius possible within chartRect + radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + // Calculate total of all series to get reference value or use total reference from optional options + totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { + return previousValue + currentValue; + }, 0); + + // 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 ? options.donutWidth / 2 : 0; + + // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius + // see https://github.com/gionkunz/chartist-js/issues/21 + labelRadius = options.donut ? radius : radius / 2; + // Add the offset to the labelRadius where a negative offset means closed to the center of the chart + labelRadius += options.labelOffset; + + // Calculate end angle based on total sum and current data value and offset with padding + var center = { + x: chartRect.x1 + chartRect.width() / 2, + y: chartRect.y2 + chartRect.height() / 2 + }; + + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = this.data.series.filter(function(val) { + return val !== 0; + }).length === 1; + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g', null, null, true); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name + }, Chartist.xmlNs.uri); + } + + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle + // with Z and use 359.99 degrees + if(endAngle - startAngle === 360) { + endAngle -= 0.01; + } + + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), + arcSweep = endAngle - startAngle <= 180 ? '0' : '1', + d = [ + // Start at the end point from the cartesian coordinates + 'M', end.x, end.y, + // Draw arc + 'A', radius, radius, 0, arcSweep, 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 === false) { + d.push('L', center.x, center.y); + } + + // Create the SVG path + // If this is a donut chart we add the donut class, otherwise just a regular slice + var path = seriesGroups[i].elem('path', { + d: d.join(' ') + }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); + + // Adding the pie series value to the path + path.attr({ + 'value': dataArray[i] + }, Chartist.xmlNs.uri); + + // If this is a donut, we add the stroke-width as style attribute + if(options.donut === true) { + path.attr({ + 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' + }); + } + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'slice', + value: dataArray[i], + totalDataSum: totalDataSum, + index: i, + group: seriesGroups[i], + element: path, + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + + // If we need to show labels we need to add the label for this slice now + if(options.showLabel) { + // Position at the labelRadius distance from center and between start and end angle + var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), + interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + + var labelElement = seriesGroups[i].elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } + + // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // (except for last slice) + startAngle = endAngle; + } + + this.eventEmitter.emit('created', { + chartRect: chartRect, + svg: this.svg, + options: options + }); + } + + /** + * This method creates a new pie chart and returns an object that can be used to redraw the chart. + * + * @memberof Chartist.Pie + * @param {String|Node} query A selector query string or directly a DOM element + * @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. + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object with a version and an update method to manually redraw the chart + * + * @example + * // Default options of the pie chart + * var defaultOptions = { + * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + * width: undefined, + * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + * height: undefined, + * // Padding of the chart drawing area to the container element and labels + * chartPadding: 5, + * // Override the class names that get used to generate the SVG structure of the chart + * classNames: { + * chart: 'ct-chart-pie', + * series: 'ct-series', + * slice: 'ct-slice', + * donut: 'ct-donut', + label: 'ct-label' + * }, + * // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. + * startAngle: 0, + * // 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. + * total: undefined, + * // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. + * donut: false, + * // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. + * donutWidth: 60, + * // If a label should be shown or not + * showLabel: true, + * // 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. + * labelOffset: 0, + * // An interpolation function for the label value + * labelInterpolationFnc: function(value, index) {return value;}, + * // 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. + * labelDirection: 'neutral' + * }; + * + * @example + * // Simple pie chart example with four series + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }); + * + * @example + * // Drawing a donut chart + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }, { + * donut: true + * }); + * + * @example + * // Using donut, startAngle and total to draw a gauge chart + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * donut: true, + * donutWidth: 20, + * startAngle: 270, + * total: 200 + * }); + * + * @example + * // Drawing a pie chart with padding and labels that are outside the pie + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * chartPadding: 30, + * labelOffset: 50, + * labelDirection: 'explode' + * }); + */ + function Pie(query, data, options, responsiveOptions) { + Chartist.Pie.super.constructor.call(this, + query, + data, + Chartist.extend({}, defaultOptions, options), + responsiveOptions); + } + + // Creating pie chart type in Chartist namespace + Chartist.Pie = Chartist.Base.extend({ + constructor: Pie, + createChart: createChart, + determineAnchorPosition: determineAnchorPosition + }); + + }(window, document, Chartist)); + + return Chartist; })); diff --git a/dist/chartist.min.css b/dist/chartist.min.css index a9db80f2..9e089c23 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.4.1 +/* Chartist.js 0.4.2 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index ce9aff64..811eb56e 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.4.1 +/* Chartist.js 0.4.2 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){return Chartist}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.2"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 4171ed6d..c21e4d87 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist"],"mappings":";;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,UAAW,WACT,MAAQF,GAAKI,oBAAsBH,MAET,gBAAZI,SAIhBC,OAAOD,QAAUJ,IAEjBD,EAAe,SAAIC,KAErBM,KAAM,WASN,MAAOC","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.1\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\n */\n\n\n return Chartist;\n\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","plugins","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","plugin","pluginFnc","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.2\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.2'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n // Plugin registry for plugin authors to register their plugins\n Chartist.plugins = {};\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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\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 var pluginFnc = Chartist.plugins[plugin.name];\n if(pluginFnc) {\n pluginFnc(this, plugin.options);\n }\n }.bind(this));\n }\n\n // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index c53518d7..1eedabb9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.4.1", + "version": "0.4.2", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index cd31f367..c09fd0d0 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.4.1' + version: '0.4.2' }; (function (window, document, Chartist) { From e56488746464a432a8b7a41dbf70ce046233666c Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 11:05:53 +0100 Subject: [PATCH 113/593] Updated plugin architecture for convenience reasons and better support for modularization --- site/code-snippets/plugin-example.js | 44 ++++++++++++++------------ site/code-snippets/plugin-include.js | 9 +++--- site/code-snippets/plugin-signature.js | 2 +- site/data/pages/plugins.yml | 28 +++++++--------- src/scripts/base.js | 7 ++-- src/scripts/core.js | 4 --- 6 files changed, 44 insertions(+), 50 deletions(-) diff --git a/site/code-snippets/plugin-example.js b/site/code-snippets/plugin-example.js index 1eef28b7..dd2adf02 100644 --- a/site/code-snippets/plugin-example.js +++ b/site/code-snippets/plugin-example.js @@ -1,24 +1,26 @@ -Chartist.plugins.ctPointLabels = function(chart, options) { - var defaultOptions = { - labelClass: 'ct-label', - labelOffset: { - x: 0, - y: -10 - }, - textAnchor: 'middle' - }; +function ctPointLabels(options) { + return function ctPointLabels(chart) { + var defaultOptions = { + labelClass: 'ct-label', + labelOffset: { + x: 0, + y: -10 + }, + textAnchor: 'middle' + }; - options = Chartist.extend({}, defaultOptions, options); + options = Chartist.extend({}, defaultOptions, options); - if(chart instanceof Chartist.Line) { - chart.on('draw', function(data) { - if(data.type === 'point') { - data.group.elem('text', { - x: data.x + options.labelOffset.x, - y: data.y + options.labelOffset.y, - style: 'text-anchor: ' + options.textAnchor - }, options.labelClass).text(data.value); - } - }); + if(chart instanceof Chartist.Line) { + chart.on('draw', function(data) { + if(data.type === 'point') { + data.group.elem('text', { + x: data.x + options.labelOffset.x, + y: data.y + options.labelOffset.y, + style: 'text-anchor: ' + options.textAnchor + }, options.labelClass).text(data.value); + } + }); + } } -}; +} diff --git a/site/code-snippets/plugin-include.js b/site/code-snippets/plugin-include.js index 36ec5cb8..f131ab50 100644 --- a/site/code-snippets/plugin-include.js +++ b/site/code-snippets/plugin-include.js @@ -5,10 +5,9 @@ var chart = new Chartist.Line('.ct-chart', { [2, 4, 2, 5, 4, 3, 6] ] }, { - plugins: [{ - name: 'chartist-plugin-pointlabels', - options: { + plugins: [ + ctPointLabels({ textAnchor: 'middle' - } - }] + }) + ] }); diff --git a/site/code-snippets/plugin-signature.js b/site/code-snippets/plugin-signature.js index ccd453c5..8c7f2776 100644 --- a/site/code-snippets/plugin-signature.js +++ b/site/code-snippets/plugin-signature.js @@ -1,3 +1,3 @@ -function myChartistPlugin(chart, options) { +function myChartistPlugin(chart) { } diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 1d4d4f25..15dfbc9b 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -21,9 +21,8 @@ sections: - type: text data: text: > - Once you have included a plugin in your project it will register itself in the Chartist.js plugin - registry. You can use registered plugins in your chart by specifying them explicitly in the plugins - section of your chart configuration. Check the List of plugins + Once you have included a plugin in your project you can use it in your chart by specifying it explicitly + in the plugins section of your chart configuration. Check the List of plugins section to see what plugins you can use. - type: code-snippet @@ -41,8 +40,9 @@ sections: - type: text data: text: > - Besides the name of the plugins you would like to use in your chart you can pass an optional - options object to the plugin. Check the individual plugin documentation for a list of valid options. + Chartist.js expects an array of plugin functions to be present in the plugins array + of the chart configuration. Usually plugins should be written as function factories so you + can pass additional parameters and options to the factory which is creating the plugin function and returns it. - title: Available plugins level: 3 @@ -72,20 +72,15 @@ sections: - title: Develop a plugin level: 3 items: - - type: text - data: - text: > - Plugins can be registered in this object with their name as property name and a plugin function as - value. Plugin names need to be chosen carefully as they can clash with each other. It's recommended - to use a prefix for plugin names. - type: text data: text: > Plugins are functions that will be called for each chart that is created with the plugin enabled - (specified in the plugins configuration of a chart). The plugin function will be called with two - arguments where the first one is the chart that is registering itself for the plugin and the second - argument which is the plugin options specified in the plugins section of the chart configuration. + (specified in the plugins configuration of a chart). The plugin function will be called with one + argument which is the chart that is registering itself for the plugin. If you wish to use some additional + parameters or configuration for your plugin initialization, it's recommended to use a function factory. + You can check the example plugin for an implementation using a function factory. - type: code-snippet data: @@ -111,8 +106,9 @@ sections: data: text: > Plugins should contain their own default settings and use Chartist.extend to override - the settings specified in the options passed to the plugin function. Using - the optionsProvider of the chart object one could also implement responsive behaviour. + the settings specified in the options passed to the plugin factory function. Using + the optionsProvider of the chart object one could also implement functioanlity based on + the chart configuration as well as responsive configuration. - type: sub-section data: diff --git a/src/scripts/base.js b/src/scripts/base.js index 8ccdb974..ad88cf73 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -101,9 +101,10 @@ // Initialize all relevant plugins with our chart object and the plugin options specified in the config if(this.options.plugins) { this.options.plugins.forEach(function(plugin) { - var pluginFnc = Chartist.plugins[plugin.name]; - if(pluginFnc) { - pluginFnc(this, plugin.options); + if(plugin instanceof Array) { + plugin[0](this, plugin[1]); + } else { + plugin(this); } }.bind(this)); } diff --git a/src/scripts/core.js b/src/scripts/core.js index c09fd0d0..6a52a8d8 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -591,7 +591,6 @@ var Chartist = { * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches * * @memberof Chartist.Core - * @param {Object} defaultOptions Default options from Chartist * @param {Object} options Options set by user * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events @@ -651,9 +650,6 @@ var Chartist = { }; }; - // Plugin registry for plugin authors to register their plugins - Chartist.plugins = {}; - //http://schepers.cc/getting-to-the-point Chartist.catmullRom2bezier = function (crp, z) { var d = []; From 5a99a99f67aab5a6642d532e25cae0536b1c1a6e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 11:07:29 +0100 Subject: [PATCH 114/593] Update to 0.4.3 --- CHANGELOG.md | 3 +++ bower.json | 2 +- dist/chartist.js | 15 ++++++--------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 ++-- dist/chartist.min.js.map | 2 +- package.json | 2 +- src/scripts/core.js | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd65fe35..ae67e8c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +v0.4.3 - 27 Nov 2014 +- Updated plugin architecture for convenience reasons and better support for modularization + v0.4.2 - 27 Nov 2014 -------------------- diff --git a/bower.json b/bower.json index e8327848..5080da90 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.4.2", + "version": "0.4.3", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 2c91a589..306beb4a 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { - /* Chartist.js 0.4.2 + /* Chartist.js 0.4.3 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.4.2' + version: '0.4.3' }; (function (window, document, Chartist) { @@ -612,7 +612,6 @@ * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches * * @memberof Chartist.Core - * @param {Object} defaultOptions Default options from Chartist * @param {Object} options Options set by user * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events @@ -672,9 +671,6 @@ }; }; - // Plugin registry for plugin authors to register their plugins - Chartist.plugins = {}; - //http://schepers.cc/getting-to-the-point Chartist.catmullRom2bezier = function (crp, z) { var d = []; @@ -1115,9 +1111,10 @@ // Initialize all relevant plugins with our chart object and the plugin options specified in the config if(this.options.plugins) { this.options.plugins.forEach(function(plugin) { - var pluginFnc = Chartist.plugins[plugin.name]; - if(pluginFnc) { - pluginFnc(this, plugin.options); + if(plugin instanceof Array) { + plugin[0](this, plugin[1]); + } else { + plugin(this); } }.bind(this)); } diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 9e089c23..3049590a 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.4.2 +/* Chartist.js 0.4.3 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 811eb56e..37933874 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.4.2 +/* Chartist.js 0.4.3 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.2"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index c21e4d87..c715d8af 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","plugins","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","plugin","pluginFnc","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.2\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.2'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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} defaultOptions Default options from Chartist\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n // Plugin registry for plugin authors to register their plugins\n Chartist.plugins = {};\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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\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 var pluginFnc = Chartist.plugins[plugin.name];\n if(pluginFnc) {\n pluginFnc(this, plugin.options);\n }\n }.bind(this));\n }\n\n // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","plugins","plugin","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":";;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,UAAW,WACT,MAAQF,GAAKI,oBAAsBH,MAET,gBAAZI,SAIhBC,OAAOD,QAAUJ,IAEjBD,EAAe,SAAIC,KAErBM,KAAM,WAYN,GAAIC,IACFC,QAAS,QAqiFX,OAliFC,UAAUC,EAAQC,EAAUH,GAC3B,YASAA,GAASI,KAAO,SAAUC,GACxB,MAAOA,IAUTL,EAASM,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAWtCL,EAASS,OAAS,SAAUC,GAC1BA,EAASA,KAET,IAAIC,GAAUC,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,EAWpD,OAVAL,GAAQM,QAAQ,SAASC,GACvB,IAAK,GAAIC,KAAQD,GAIbR,EAAOS,GAHmB,gBAAjBD,GAAOC,IAAwBD,EAAOC,YAAiBP,OAGjDM,EAAOC,GAFPnB,EAASS,OAAOC,EAAOS,GAAOD,EAAOC,MAOnDT,GAUTV,EAASoB,UAAY,SAASC,GAK5B,MAJoB,gBAAVA,KACRA,EAAQA,EAAMC,QAAQ,eAAgB,MAGhCD,GAWVrB,EAASuB,WAAa,SAASF,EAAOG,GAKpC,MAJoB,gBAAVH,KACRA,GAAgBG,GAGXH,GAUTrB,EAASyB,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQvB,EAASsB,cAAcC,IAahE1B,EAAS4B,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIC,EAqBJ,OAnBAH,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAEnBE,EAAMJ,EAAUJ,cAAc,OAC3BQ,GACDJ,EAAUK,YAAYD,GAIxBA,EAAM,GAAIjC,GAASmC,IAAI,OAAOC,MAC5BN,MAAOA,EACPC,OAAQA,IACPM,SAASL,GAAWI,MACrBE,MAAO,UAAYR,EAAQ,aAAeC,EAAS,MAIrDF,EAAUU,YAAYN,EAAIO,OAEnBP,GAUTjC,EAASyC,aAAe,SAAUC,GAGhC,IAAK,GAFDC,MAEKC,EAAI,EAAGA,EAAIF,EAAKG,OAAOC,OAAQF,IAAK,CAG3CD,EAAMC,GAAgC,gBAApBF,GAAKG,OAAOD,IAA4CG,SAAxBL,EAAKG,OAAOD,GAAGF,KAC/DA,EAAKG,OAAOD,GAAGF,KAAOA,EAAKG,OAAOD,EAGpC,KAAK,GAAII,GAAI,EAAGA,EAAIL,EAAMC,GAAGE,OAAQE,IACnCL,EAAMC,GAAGI,IAAML,EAAMC,GAAGI,GAI5B,MAAOL,IAWT3C,EAASiD,mBAAqB,SAAUC,EAAWJ,GACjD,IAAK,GAAIF,GAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IACpC,GAAIM,EAAUN,GAAGE,SAAWA,EAI5B,IAAK,GAAIE,GAAIE,EAAUN,GAAGE,OAAYA,EAAJE,EAAYA,IAC5CE,EAAUN,GAAGI,GAAK,CAItB,OAAOE,IAUTlD,EAASmD,iBAAmB,SAAU9B,GACpC,MAAO+B,MAAKC,MAAMD,KAAKE,IAAIF,KAAKG,IAAIlC,IAAU+B,KAAKI,OAarDxD,EAASyD,cAAgB,SAAUxB,EAAKa,EAAQY,EAAQC,GACtD,GAAIC,GAAkB5D,EAAS6D,mBAAmB5B,EAAK0B,EACvD,OAAQb,GAASY,EAAOI,MAAQF,GAWlC5D,EAAS6D,mBAAqB,SAAU5B,EAAK0B,GAC3C,MAAOP,MAAKW,KAAK/D,EAASoB,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAoC,EAAvB4B,EAAQK,aAAoBL,EAAQM,MAAMC,OAAQ,IAU5HlE,EAASmE,WAAa,SAAUjB,GAC9B,GAAIN,GACFI,EACAoB,GACEC,MAAOC,OAAOC,UACdC,IAAKF,OAAOC,UAGhB,KAAK3B,EAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IAChC,IAAKI,EAAI,EAAGA,EAAIE,EAAUN,GAAGE,OAAQE,IAC/BE,EAAUN,GAAGI,GAAKoB,EAAQC,OAC5BD,EAAQC,KAAOnB,EAAUN,GAAGI,IAG1BE,EAAUN,GAAGI,GAAKoB,EAAQI,MAC5BJ,EAAQI,IAAMtB,EAAUN,GAAGI,GAKjC,OAAOoB,IAcTpE,EAASyE,UAAY,SAAUxC,EAAKyC,EAAgBf,EAASgB,GAC3D,GAAI/B,GACFgC,EACAC,EACAnB,EAAS1D,EAASmE,WAAWO,EAG/BhB,GAAOW,MAAQV,EAAQU,OAA0B,IAAjBV,EAAQU,KAAa,EAAIX,EAAOW,MAChEX,EAAOc,KAAOb,EAAQa,MAAwB,IAAhBb,EAAQa,IAAY,EAAId,EAAOc,KAI1Dd,EAAOW,OAASX,EAAOc,MAEN,IAAfd,EAAOc,IACRd,EAAOW,KAAO,EACNX,EAAOc,IAAM,EAErBd,EAAOW,KAAO,EAGdX,EAAOc,IAAM,IAObG,GAAqC,IAAnBA,KACpBjB,EAAOW,KAAOjB,KAAKW,IAAIY,EAAgBjB,EAAOW,MAC9CX,EAAOc,IAAMpB,KAAK0B,IAAIH,EAAgBjB,EAAOc,MAG/Cd,EAAOqB,WAAarB,EAAOW,KAAOX,EAAOc,IACzCd,EAAOsB,IAAMhF,EAASmD,iBAAiBO,EAAOqB,YAC9CrB,EAAOoB,IAAM1B,KAAKC,MAAMK,EAAOc,IAAMpB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOK,IAAMX,KAAK8B,KAAKxB,EAAOW,KAAOjB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IACnCpB,EAAOyB,KAAO/B,KAAK6B,IAAI,GAAIvB,EAAOsB,KAClCtB,EAAO0B,cAAgBhC,KAAKiC,MAAM3B,EAAOI,MAAQJ,EAAOyB,KAOxD,KAHA,GAAIrC,GAAS9C,EAASyD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,GAC5D2B,EAAUxC,EAASa,EAAQ4B,MAAMC,gBAGjC,GAAIF,GAAWtF,EAASyD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,IAAYA,EAAQ4B,MAAMC,cACxF9B,EAAOyB,MAAQ,MACV,CAAA,GAAKG,KAAWtF,EAASyD,cAAcxB,EAAKyB,EAAOyB,KAAO,EAAGzB,EAAQC,IAAYA,EAAQ4B,MAAMC,eAGpG,KAFA9B,GAAOyB,MAAQ,EASnB,IAFAP,EAASlB,EAAOoB,IAChBD,EAASnB,EAAOK,IACXnB,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAC5CvC,EAAIc,EAAOyB,KAAOzB,EAAOc,MAC3BI,GAAUlB,EAAOyB,MAGfvC,EAAIc,EAAOyB,MAAQzB,EAAOW,OAC5BQ,GAAUnB,EAAOyB,KAQrB,KALAzB,EAAOoB,IAAMF,EACblB,EAAOK,IAAMc,EACbnB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IAEnCpB,EAAO+B,UACF7C,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAChDzB,EAAO+B,OAAOC,KAAK9C,EAGrB,OAAOc,IAaT1D,EAAS2F,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAM3C,KAAK6C,GAAK,GAEvD,QACEC,EAAGN,EAAWE,EAAS1C,KAAK+C,IAAIH,GAChCI,EAAGP,EAAWC,EAAS1C,KAAKiD,IAAIL,KAYpChG,EAASsG,gBAAkB,SAAUrE,EAAK0B,GACxC,GAAI4C,GAAU5C,EAAQ4B,MAAQ5B,EAAQ4B,MAAMrB,OAAS,EACnDsC,EAAU7C,EAAQM,MAAQN,EAAQM,MAAMC,OAAS,CAEnD,QACEuC,GAAI9C,EAAQK,aAAeuC,EAC3BG,GAAItD,KAAKW,KAAK/D,EAASoB,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAY4B,EAAQK,aAAewC,EAAS7C,EAAQK,cAC5G2C,GAAIvD,KAAKW,KAAK/D,EAASoB,UAAUuC,EAAQ7B,QAAUG,EAAIH,SAAW6B,EAAQK,aAAcL,EAAQK,aAAeuC,GAC/GK,GAAIjD,EAAQK,aACZlC,MAAO,WACL,MAAO/B,MAAK4G,GAAK5G,KAAK0G,IAExB1E,OAAQ,WACN,MAAOhC,MAAK2G,GAAK3G,KAAK6G,MAe5B5G,EAAS6G,YAAc,SAASC,EAAQC,EAAMC,EAAYhF,EAAWiF,GACnE,GAAGA,EAAuB,CACxB,GAAIC,GAAU,gBAAkBlF,EAAY,KAAO+E,EAAO,SAC1D,OAAOD,GAAOK,cAAcD,EAASF,GAErC,MAAOF,GAAOM,KAAK,OAAQJ,EAAYhF,GAAW+E,KAAKA,IAgB3D/G,EAASqH,YAAc,SAAUC,EAAW5E,EAAM6E,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAErFvE,EAAK8E,OAAOvG,QAAQ,SAAUI,EAAOqG,GACnC,GAAIC,GAAoBhE,EAAQM,MAAM2D,sBAAsBvG,EAAOqG,GACjE5F,EAAQwF,EAAUxF,QAAUY,EAAK8E,OAAO1E,OACxCf,EAAS4B,EAAQM,MAAMC,OACvB2D,EAAMP,EAAUb,GAAK3E,EAAQ4F,CAG/B,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIhE,EAAQM,MAAM6D,SAAU,CAC1B,GAAIC,GAAcR,EAAKH,KAAK,QAC1BX,GAAIoB,EACJnB,GAAIY,EAAUZ,GACdC,GAAIkB,EACJjB,GAAIU,EAAUV,KACZjD,EAAQqE,WAAWT,KAAM5D,EAAQqE,WAAWC,YAAYC,KAAK,KAGjET,GAAaU,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASR,EACTtB,GAAIoB,EACJnB,GAAIY,EAAUZ,GACdC,GAAIkB,EACJjB,GAAIU,EAAUV,KAIlB,GAAIjD,EAAQM,MAAMuE,UAAW,CAC3B,GAAIC,IACFvC,EAAG2B,EAAMlE,EAAQM,MAAMyE,YAAYxC,EACnCE,EAAGkB,EAAUZ,GAAK/C,EAAQM,MAAMyE,YAAYtC,GAAKa,EAAwB,EAAI,KAG3E0B,EAAe3I,EAAS6G,YAAYW,EAAQ,GAAKG,GACnDzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQqE,WAAWY,MAAOjF,EAAQqE,WAAWC,YAAYC,KAAK,KAAMjB,EAExEQ,GAAaU,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOd,EACPe,QAASI,EACT5B,KAAM,GAAKY,EACXzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EAER8G,GAAIC,SAEF,MADA5I,GAAO6I,QAAQC,KAAK,mEACbjJ,KAAK+B,cAmBtB9B,EAASiJ,YAAc,SAAU3B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAEvFvD,EAAO+B,OAAOxE,QAAQ,SAAUI,EAAOqG,GACrC,GAAIC,GAAoBhE,EAAQ4B,MAAMqC,sBAAsBvG,EAAOqG,GACjE5F,EAAQ6B,EAAQ4B,MAAMrB,OACtBnC,EAASuF,EAAUvF,SAAW2B,EAAO+B,OAAO3C,OAC5C+E,EAAMP,EAAUZ,GAAK3E,EAAS2F,CAGhC,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIhE,EAAQ4B,MAAMuC,SAAU,CAC1B,GAAIC,GAAcR,EAAKH,KAAK,QAC1BX,GAAIa,EAAUb,GACdC,GAAImB,EACJlB,GAAIW,EAAUX,GACdC,GAAIiB,IACFlE,EAAQqE,WAAWT,KAAM5D,EAAQqE,WAAWkB,UAAUhB,KAAK,KAG/DT,GAAaU,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASR,EACTtB,GAAIa,EAAUb,GACdC,GAAImB,EACJlB,GAAIW,EAAUX,GACdC,GAAIiB,IAIR,GAAIlE,EAAQ4B,MAAMiD,UAAW,CAC3B,GAAIC,IACFvC,EAAGvC,EAAQK,aAAeL,EAAQ4B,MAAMmD,YAAYxC,GAAKe,EAAwB,IAAM,GACvFb,EAAGyB,EAAMlE,EAAQ4B,MAAMmD,YAAYtC,GAAKa,EAAwB,IAAM,IAGpE0B,EAAe3I,EAAS6G,YAAYW,EAAQ,GAAKG,GACnDzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQqE,WAAWY,MAAOjF,EAAQqE,WAAWkB,UAAUhB,KAAK,KAAMjB,EAEtEQ,GAAaU,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOd,EACPe,QAASI,EACT5B,KAAM,GAAKY,EACXzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EAER8G,GAAIC,SAEF,MADA5I,GAAO6I,QAAQC,KAAK,mEACbjJ,KAAKgC,eAiBtB/B,EAASmJ,aAAe,SAAU7B,EAAW5D,EAAQhB,EAAMgF,GACzD,OACExB,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAUY,EAAKI,OAAS4E,EACpDtB,EAAGkB,EAAUZ,GAAKY,EAAUvF,UAAYW,EAAKgF,GAAShE,EAAOoB,MAAQpB,EAAOI,MAAQJ,EAAOyB,QAc/FnF,EAASoJ,gBAAkB,SAAUzF,EAAS0F,EAAmB5B,GAM/D,QAAS6B,KACP,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiBxJ,EAASS,UAAWgJ,GAEjCJ,EACF,IAAKzG,EAAI,EAAGA,EAAIyG,EAAkBvG,OAAQF,IAAK,CAC7C,GAAI8G,GAAMxJ,EAAOyJ,WAAWN,EAAkBzG,GAAG,GAC7C8G,GAAIE,UACNJ,EAAiBxJ,EAASS,OAAO+I,EAAgBH,EAAkBzG,GAAG,KAKzE6E,GACDA,EAAaU,KAAK,kBAChBoB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoB7I,QAAQ,SAASyI,GACnCA,EAAIK,eAAeT,KA5BvB,GACEE,GAEA5G,EAHE6G,EAAczJ,EAASS,UAAWkD,GAEpCmG,IA8BF,KAAK5J,EAAOyJ,WACV,KAAM,iEACD,IAAIN,EAET,IAAKzG,EAAI,EAAGA,EAAIyG,EAAkBvG,OAAQF,IAAK,CAC7C,GAAI8G,GAAMxJ,EAAOyJ,WAAWN,EAAkBzG,GAAG,GACjD8G,GAAIM,YAAYV,GAChBQ,EAAoBpE,KAAKgE,GAM7B,MAFAJ,MAGET,GAAIW,kBACF,MAAOxJ,GAASS,UAAW+I,IAE7BK,0BAA2BA,IAK/B7J,EAASiK,kBAAoB,SAAUC,EAAKC,GAE1C,IAAK,GADDC,MACKxH,EAAI,EAAGyH,EAAOH,EAAIpH,OAAQuH,EAAO,GAAKF,EAAIvH,EAAGA,GAAK,EAAG,CAC5D,GAAI0H,KACDpE,GAAIgE,EAAItH,EAAI,GAAIwD,GAAI8D,EAAItH,EAAI,KAC5BsD,GAAIgE,EAAItH,GAAIwD,GAAI8D,EAAItH,EAAI,KACxBsD,GAAIgE,EAAItH,EAAI,GAAIwD,GAAI8D,EAAItH,EAAI,KAC5BsD,GAAIgE,EAAItH,EAAI,GAAIwD,GAAI8D,EAAItH,EAAI,IAE3BuH,GACGvH,EAEMyH,EAAO,IAAMzH,EACtB0H,EAAE,IAAMpE,GAAIgE,EAAI,GAAI9D,GAAI8D,EAAI,IACnBG,EAAO,IAAMzH,IACtB0H,EAAE,IAAMpE,GAAIgE,EAAI,GAAI9D,GAAI8D,EAAI,IAC5BI,EAAE,IAAMpE,GAAIgE,EAAI,GAAI9D,GAAI8D,EAAI,KAL5BI,EAAE,IAAMpE,GAAIgE,EAAIG,EAAO,GAAIjE,GAAI8D,EAAIG,EAAO,IAQxCA,EAAO,IAAMzH,EACf0H,EAAE,GAAKA,EAAE,GACC1H,IACV0H,EAAE,IAAMpE,GAAIgE,EAAItH,GAAIwD,GAAI8D,EAAItH,EAAI,KAGpCwH,EAAE1E,QAEI4E,EAAE,GAAGpE,EAAI,EAAIoE,EAAE,GAAGpE,EAAIoE,EAAE,GAAGpE,GAAK,IAChCoE,EAAE,GAAGlE,EAAI,EAAIkE,EAAE,GAAGlE,EAAIkE,EAAE,GAAGlE,GAAK,GACjCkE,EAAE,GAAGpE,EAAI,EAAIoE,EAAE,GAAGpE,EAAIoE,EAAE,GAAGpE,GAAK,GAChCoE,EAAE,GAAGlE,EAAI,EAAIkE,EAAE,GAAGlE,EAAIkE,EAAE,GAAGlE,GAAK,EACjCkE,EAAE,GAAGpE,EACLoE,EAAE,GAAGlE,IAKX,MAAOgE,KAGTlK,OAAQC,SAAUH,GAOnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAASuK,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAO/E,KAAKgF,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAO3H,cACV6H,GAASF,UAIXE,GAASF,IAYtB,QAAStC,GAAKsC,EAAO/H,GAEhBiI,EAASF,IACVE,EAASF,GAAOxJ,QAAQ,SAASyJ,GAC/BA,EAAQhI,KAKTiI,EAAS,MACVA,EAAS,KAAK1J,QAAQ,SAAS8J,GAC7BA,EAAYN,EAAO/H,KAvDzB,GAAIiI,KA4DJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpBzC,KAAMA,KAIVjI,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAASgL,GAAYC,GACnB,GAAIC,KACJ,IAAID,EAAKnI,OACP,IAAK,GAAIF,GAAI,EAAGA,EAAIqI,EAAKnI,OAAQF,IAC/BsI,EAAIxF,KAAKuF,EAAKrI,GAGlB,OAAOsI,GA4CT,QAASzK,GAAO0K,EAAYC,GAC1B,GAAIC,GAAaD,GAAsBrL,KAAKc,WAAab,EAASsL,MAC9DC,EAAQC,OAAOC,OAAOJ,EAE1BrL,GAASsL,MAAMI,iBAAiBH,EAAOJ,EAEvC,IAAIQ,GAAS,WACX,GACEC,GADEC,EAAKN,EAAMO,aAAe,YAU9B,OALAF,GAAW7L,OAASC,EAAWwL,OAAOC,OAAOF,GAASxL,KACtD8L,EAAGE,MAAMH,EAAUhL,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,IAIlD4K,EAOT,OAJAD,GAAO9K,UAAY0K,EACnBI,EAAOK,MAAQX,EACfM,EAAOlL,OAASV,KAAKU,OAEdkL,EA0FT,QAASM,GAAIC,EAAaf,GACxB,GAAGpL,OAASC,EAASsL,MACnB,KAAM,IAAIa,OAAM,iFAIlB,IAAIC,QACDC,OAAOH,GACPI,IAAI,SAAUzL,GACb,MAAOA,aAAqB0L,UAAW1L,EAAUA,UAAYA,IAG7D2L,EAAkBxM,EAASsL,MAAMI,iBAAiBK,MAAMhJ,OAAWqJ,EAGvE,cADOI,GAAgBV,YAChB/L,KAAKU,OAAO0K,EAAYqB,GAIjC,QAASd,KACP,GAAIe,GAAOzB,EAAYhK,WACnBN,EAAS+L,EAAK,EAYlB,OAVAA,GAAK5B,OAAO,EAAG4B,EAAK3J,OAAS,GAAG7B,QAAQ,SAAUC,GAChDsK,OAAOkB,oBAAoBxL,GAAQD,QAAQ,SAAU0L,SAE5CjM,GAAOiM,GAEdnB,OAAOoB,eAAelM,EAAQiM,EAC5BnB,OAAOqB,yBAAyB3L,EAAQyL,QAIvCjM,EAGTV,EAASsL,OACP7K,OAAQA,EACRwL,IAAKA,EACLP,iBAAkBA,IAGpBxL,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAaA,SAAS8M,KAEP,MADA/M,MAAKgN,YAAYhN,KAAKqJ,gBAAgBI,gBAC/BzJ,KAQT,QAASiN,KAGP,MAFA9M,GAAO+M,oBAAoB,SAAUlN,KAAKmN,gBAC1CnN,KAAKqJ,gBAAgBS,4BACd9J,KAUT,QAASoN,GAAG1C,EAAOC,GAEjB,MADA3K,MAAK0H,aAAa+C,gBAAgBC,EAAOC,GAClC3K,KAUT,QAASqN,GAAI3C,EAAOC,GAElB,MADA3K,MAAK0H,aAAamD,mBAAmBH,EAAOC,GACrC3K,KAYT,QAASsN,GAAK3L,EAAOgB,EAAMiB,EAAS0F,GAClCtJ,KAAK8B,UAAY7B,EAASyB,cAAcC,GACxC3B,KAAK2C,KAAOA,EACZ3C,KAAK4D,QAAUA,EACf5D,KAAKsJ,kBAAoBA,EACzBtJ,KAAK0H,aAAezH,EAASuK,eAC7BxK,KAAKkH,sBAAwBjH,EAASmC,IAAImL,YAAY,iBACtDvN,KAAKwN,mBAAqBvN,EAASmC,IAAImL,YAAY,4BACnDvN,KAAKmN,eAAiB,WACpBnN,KAAK+M,UACLU,KAAKzN,MAEJA,KAAK8B,YAEH9B,KAAK8B,UAAU4L,cAChB1N,KAAK8B,UAAU4L,aAAaT,SAG9BjN,KAAK8B,UAAU4L,aAAe1N,MAGhCG,EAAOwN,iBAAiB,SAAU3N,KAAKmN,gBAIvCS,WAAW,WAGT5N,KAAKqJ,gBAAkBpJ,EAASoJ,gBAAgBrJ,KAAK4D,QAAS5D,KAAKsJ,kBAAmBtJ,KAAK0H,cAIxF1H,KAAK4D,QAAQiK,SACd7N,KAAK4D,QAAQiK,QAAQ3M,QAAQ,SAAS4M,GACjCA,YAAkBjN,OACnBiN,EAAO,GAAG9N,KAAM8N,EAAO,IAEvBA,EAAO9N,OAETyN,KAAKzN,OAITA,KAAKgN,YAAYhN,KAAKqJ,gBAAgBI,iBACtCgE,KAAKzN,MAAO,GAIhBC,EAASqN,KAAOrN,EAASsL,MAAM7K,QAC7BqL,YAAauB,EACbjE,gBAAiBrG,OACjBlB,UAAWkB,OACXd,IAAKc,OACL0E,aAAc1E,OACdgK,YAAa,WACX,KAAM,IAAIZ,OAAM,2CAElBW,OAAQA,EACRE,OAAQA,EACRG,GAAIA,EACJC,IAAKA,EACLnN,QAASD,EAASC,QAClBgH,uBAAuB,KAGzB/G,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAuBA,SAASmC,GAAI2L,EAAM9G,EAAYhF,EAAW8E,EAAQiH,GAE7CD,YAAgBE,YACjBjO,KAAKyC,MAAQsL,GAEb/N,KAAKyC,MAAQrC,EAAS8N,gBAAgBC,EAAOJ,GAGjC,QAATA,GACD/N,KAAKyC,MAAM2L,eAAeC,EAAOpO,EAASoO,MAAMC,cAAerO,EAASoO,MAAME,KAG7EtH,GACDjH,KAAKqC,KAAK4E,GAGThF,GACDjC,KAAKsC,SAASL,GAGb8E,IACGiH,GAAejH,EAAOtE,MAAM+L,WAC9BzH,EAAOtE,MAAMgM,aAAazO,KAAKyC,MAAOsE,EAAOtE,MAAM+L,YAEnDzH,EAAOtE,MAAMD,YAAYxC,KAAKyC,SActC,QAASJ,GAAK4E,EAAYyH,GACxB,MAAyB,gBAAfzH,GACLyH,EACM1O,KAAKyC,MAAMkM,eAAeD,EAAIzH,GAE9BjH,KAAKyC,MAAMmM,aAAa3H,IAInCwE,OAAOoD,KAAK5H,GAAY/F,QAAQ,SAAS4N,GAEhB9L,SAApBiE,EAAW6H,KAIXJ,EACD1O,KAAKyC,MAAM2L,eAAeM,GAAKzO,EAASoO,MAAMU,OAAQ,IAAKD,GAAK3G,KAAK,IAAKlB,EAAW6H,IAErF9O,KAAKyC,MAAMuM,aAAaF,EAAK7H,EAAW6H,MAE1CrB,KAAKzN,OAEAA,MAaT,QAASqH,GAAK0G,EAAM9G,EAAYhF,EAAW+L,GACzC,MAAO,IAAI/N,GAASmC,IAAI2L,EAAM9G,EAAYhF,EAAWjC,KAAMgO,GAQ7D,QAASjH,KACP,MAAO/G,MAAKyC,MAAMwM,qBAAsBhB,YAAa,GAAIhO,GAASmC,IAAIpC,KAAKyC,MAAMwM,YAAc,KAQjG,QAASxP,KAEP,IADA,GAAIyP,GAAOlP,KAAKyC,MACQ,QAAlByM,EAAKC,UACTD,EAAOA,EAAKD,UAEd,OAAO,IAAIhP,GAASmC,IAAI8M,GAS1B,QAASxN,GAAc0N,GACrB,GAAIC,GAAYrP,KAAKyC,MAAMf,cAAc0N,EACzC,OAAOC,GAAY,GAAIpP,GAASmC,IAAIiN,GAAa,KASnD,QAASC,GAAiBF,GACxB,GAAIG,GAAavP,KAAKyC,MAAM6M,iBAAiBF,EAC7C,OAAOG,GAAWxM,OAAS,GAAI9C,GAASmC,IAAIoN,KAAKD,GAAc,KAajE,QAASnI,GAAcD,EAASF,EAAYhF,EAAW+L,GAGrD,GAAsB,gBAAZ7G,GAAsB,CAC9B,GAAIrF,GAAY1B,EAASqP,cAAc,MACvC3N,GAAU4N,UAAYvI,EACtBA,EAAUrF,EAAU0M,WAItBrH,EAAQ6H,aAAa,QAASW,EAI9B,IAAIC,GAAQ5P,KAAKqH,KAAK,gBAAiBJ,EAAYhF,EAAW+L,EAK9D,OAFA4B,GAAMnN,MAAMD,YAAY2E,GAEjByI,EAUT,QAAS5I,GAAK6I,GAEZ,MADA7P,MAAKyC,MAAMD,YAAYpC,EAAS0P,eAAeD,IACxC7P,KAST,QAAS+P,KACP,KAAO/P,KAAKyC,MAAM+L,YAChBxO,KAAKyC,MAAMN,YAAYnC,KAAKyC,MAAM+L,WAGpC,OAAOxO,MAST,QAASgQ,KAEP,MADAhQ,MAAKyC,MAAMwM,WAAW9M,YAAYnC,KAAKyC,OAChC,GAAIxC,GAASmC,IAAIpC,KAAKyC,MAAMwM,YAUrC,QAAS1N,GAAQ0O,GAEf,MADAjQ,MAAKyC,MAAMwM,WAAWiB,aAAaD,EAAWxN,MAAOzC,KAAKyC,OACnDwN,EAWT,QAASE,GAAO3H,EAASwF,GAOvB,MANGA,IAAehO,KAAKyC,MAAM+L,WAC3BxO,KAAKyC,MAAMgM,aAAajG,EAAQ/F,MAAOzC,KAAKyC,MAAM+L,YAElDxO,KAAKyC,MAAMD,YAAYgG,EAAQ/F,OAG1BzC,KAST,QAASoQ,KACP,MAAOpQ,MAAKyC,MAAMmM,aAAa,SAAW5O,KAAKyC,MAAMmM,aAAa,SAASyB,OAAOC,MAAM,UAU1F,QAAShO,GAASiO,GAShB,MARAvQ,MAAKyC,MAAMuM,aAAa,QACtBhP,KAAKoQ,QAAQpQ,KAAKyC,OACf6J,OAAOiE,EAAMF,OAAOC,MAAM,QAC1BE,OAAO,SAASnJ,EAAMS,EAAK2I,GAC1B,MAAOA,GAAK1F,QAAQ1D,KAAUS,IAC7BK,KAAK,MAGLnI,KAUT,QAAS0Q,GAAYH,GACnB,GAAII,GAAiBJ,EAAMF,OAAOC,MAAM,MAMxC,OAJAtQ,MAAKyC,MAAMuM,aAAa,QAAShP,KAAKoQ,QAAQpQ,KAAKyC,OAAO+N,OAAO,SAASzC,GACxE,MAAwC,KAAjC4C,EAAe5F,QAAQgD,KAC7B5F,KAAK,MAEDnI,KAST,QAAS4Q,KAGP,MAFA5Q,MAAKyC,MAAMuM,aAAa,QAAS,IAE1BhP,KAUT,QAASgC,KACP,MAAOhC,MAAKyC,MAAMoO,cAAgBxN,KAAKiC,MAAMtF,KAAKyC,MAAMqO,UAAU9O,SAAWhC,KAAKyC,MAAMwM,WAAW4B,aAUrG,QAAS9O,KACP,MAAO/B,MAAKyC,MAAMsO,aAAe1N,KAAKiC,MAAMtF,KAAKyC,MAAMqO,UAAU/O,QAAU/B,KAAKyC,MAAMwM,WAAW8B,YA4CnG,QAASC,GAAQC,EAAYC,EAAQxJ,GAiGnC,MAhGc1E,UAAXkO,IACDA,GAAS,GAGXzF,OAAOoD,KAAKoC,GAAY/P,QAAQ,SAAoCiQ,GAElE,QAASC,GAAcC,EAAqBH,GAC1C,GACEF,GACAM,EACAC,EAHEC,IAODH,GAAoBE,SAErBA,EAASF,EAAoBE,iBAAkB1Q,OAC7CwQ,EAAoBE,OACpBtR,EAASmC,IAAIqP,OAAOJ,EAAoBE,cACnCF,GAAoBE,QAI7BF,EAAoBK,MAAQzR,EAASuB,WAAW6P,EAAoBK,MAAO,MAC3EL,EAAoBM,IAAM1R,EAASuB,WAAW6P,EAAoBM,IAAK,MAEpEJ,IACDF,EAAoBO,SAAW,SAC/BP,EAAoBQ,WAAaN,EAAOpJ,KAAK,KAC7CkJ,EAAoBS,SAAW,OAI9BZ,IACDG,EAAoBU,KAAO,SAE3BP,EAAoBL,GAAaE,EAAoBW,KACrDhS,KAAKqC,KAAKmP,GAIVF,EAAUrR,EAASoB,UAAUgQ,EAAoBK,OAAS,GAC1DL,EAAoBK,MAAQ,cAG9BV,EAAUhR,KAAKqH,KAAK,UAAWpH,EAASS,QACtCuR,cAAed,GACdE,IAEAH,GAEDtD,WAAW,WACToD,EAAQvO,MAAMyP,gBACbZ,GAGF5J,GACDsJ,EAAQvO,MAAMkL,iBAAiB,aAAc,WAC3CjG,EAAaU,KAAK,kBAChBI,QAASxI,KACTgR,QAASA,EAAQvO,MACjB0P,OAAQd,KAEV5D,KAAKzN,OAGTgR,EAAQvO,MAAMkL,iBAAiB,WAAY,WACtCjG,GACDA,EAAaU,KAAK,gBAChBI,QAASxI,KACTgR,QAASA,EAAQvO,MACjB0P,OAAQd,IAITH,IAEDM,EAAoBL,GAAaE,EAAoBe,GACrDpS,KAAKqC,KAAKmP,GAEVR,EAAQhB,WAEVvC,KAAKzN,OAINiR,EAAWE,YAAsBtQ,OAClCoQ,EAAWE,GAAWjQ,QAAQ,SAASmQ,GACrCD,EAAc3D,KAAKzN,MAAMqR,GAAqB,IAC9C5D,KAAKzN,OAEPoR,EAAc3D,KAAKzN,MAAMiR,EAAWE,GAAYD,IAGlDzD,KAAKzN,OAEAA,KA+ET,QAASqS,GAAQC,GACf,GAAIpH,GAAOlL,IAEXA,MAAKuS,cACL,KAAI,GAAI1P,GAAI,EAAGA,EAAIyP,EAASvP,OAAQF,IAClC7C,KAAKuS,YAAY5M,KAAK,GAAI1F,GAASmC,IAAIkQ,EAASzP,IAIlD4I,QAAOoD,KAAK5O,EAASmC,IAAItB,WAAW0P,OAAO,SAASgC,GAClD,MAQ4C,MARpC,cACJ,SACA,gBACA,mBACA,UACA,SACA,UACA,SACA,SAASzH,QAAQyH,KACpBtR,QAAQ,SAASsR,GAClBtH,EAAKsH,GAAqB,WACxB,GAAI9F,GAAO7L,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,EAIjD,OAHAiK,GAAKqH,YAAYrR,QAAQ,SAASsH,GAChCvI,EAASmC,IAAItB,UAAU0R,GAAmBxG,MAAMxD,EAASkE,KAEpDxB,KAnjBb,GAAIiD,GAAQ,6BACVE,EAAQ,gCACRsB,EAAU,8BAEZ1P,GAASoO,OACPC,cAAe,WACfS,OAAQ,KACRR,IAAK,6CAucPtO,EAASmC,IAAMnC,EAASsL,MAAM7K,QAC5BqL,YAAa3J,EACbC,KAAMA,EACNgF,KAAMA,EACNN,OAAQA,EACRtH,KAAMA,EACNiC,cAAeA,EACf4N,iBAAkBA,EAClBlI,cAAeA,EACfJ,KAAMA,EACN+I,MAAOA,EACPC,OAAQA,EACRzO,QAASA,EACT4O,OAAQA,EACRC,QAASA,EACT9N,SAAUA,EACVoO,YAAaA,EACbE,iBAAkBA,EAClB5O,OAAQA,EACRD,MAAOA,EACPiP,QAASA,IAUX/Q,EAASmC,IAAImL,YAAc,SAASkF,GAClC,MAAOrS,GAASsS,eAAeC,WAAW,sCAAwCF,EAAS,OAQ7F,IAAIG,IACFC,YAAa,IAAM,EAAG,KAAO,MAC7BC,aAAc,IAAM,KAAO,KAAO,GAClCC,eAAgB,KAAO,IAAM,IAAM,KACnCC,YAAa,IAAM,KAAO,IAAM,KAChCC,aAAc,IAAM,IAAM,IAAM,KAChCC,eAAgB,KAAO,IAAM,KAAO,MACpCC,aAAc,IAAM,KAAO,KAAO,KAClCC,cAAe,KAAO,IAAM,KAAO,GACnCC,gBAAiB,KAAO,KAAO,KAAO,GACtCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,KAAO,IAAM,IAAM,GAClCC,gBAAiB,IAAM,EAAG,KAAO,GACjCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,IAAM,EAAG,IAAM,GAC9BC,gBAAiB,IAAM,EAAG,IAAM,GAChCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,IAAM,EAAG,IAAM,GAC7BC,eAAgB,EAAG,EAAG,EAAG,GACzBC,YAAa,GAAK,IAAM,IAAM,MAC9BC,aAAc,KAAO,IAAM,KAAO,GAClCC,eAAgB,KAAO,KAAO,IAAM,KACpCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,KAAO,KAAO,IAAM,OAClCC,eAAgB,KAAO,IAAM,KAAO,MAGtCnU,GAASmC,IAAIqP,OAASmB,EAwCtB3S,EAASmC,IAAIoN,KAAOvP,EAASsL,MAAM7K,QACjCqL,YAAasG,KAGflS,OAAQC,SAAUH,GASnB,SAASE,EAAQC,EAAUH,GAC1B,YAiDA,SAAS+M,GAAYpJ,GACnB,GACED,GADE0Q,KAEF1P,EAAiB1E,EAASiD,mBAAmBjD,EAASyC,aAAa1C,KAAK2C,MAAO3C,KAAK2C,KAAK8E,OAAO1E,OAGlG/C,MAAKkC,IAAMjC,EAAS4B,UAAU7B,KAAK8B,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQqE,WAAWqM,OAGhG3Q,EAAS1D,EAASyE,UAAU1E,KAAKkC,IAAKyC,EAAgBf,EAEtD,IAAI2D,GAAYtH,EAASsG,gBAAgBvG,KAAKkC,IAAK0B,GAE/C6D,EAASzH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWsM,YAC1D/M,EAAOxH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWuM,UAExDvU,GAASqH,YAAYC,EAAWvH,KAAK2C,KAAM6E,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,uBAC1FjH,EAASiJ,YAAY3B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAI7C,KAAK2C,KAAKG,OAAOC,OAAQF,IAAK,CAChDwR,EAAaxR,GAAK7C,KAAKkC,IAAImF,KAAK,KAG7BrH,KAAK2C,KAAKG,OAAOD,GAAGkL,MACrBsG,EAAaxR,GAAGR,MACdoS,cAAezU,KAAK2C,KAAKG,OAAOD,GAAGkL,MAClC9N,EAASoO,MAAME,KAIpB8F,EAAaxR,GAAGP,UACdsB,EAAQqE,WAAWnF,OAClB9C,KAAK2C,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQqE,WAAWnF,OAAS,IAAM7C,EAASM,cAAcsC,IAC3FsF,KAAK,KAMP,KAAK,GAJDoC,GAEFmK,EADAC,KAGO1R,EAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAC5CsH,EAAItK,EAASmJ,aAAa7B,EAAW5D,EAAQgB,EAAe9B,GAAII,GAChE0R,EAAgBhP,KAAK4E,EAAEpE,EAAGoE,EAAElE,GAIxBzC,EAAQgR,YACVF,EAAQL,EAAaxR,GAAGwE,KAAK,QAC3BX,GAAI6D,EAAEpE,EACNQ,GAAI4D,EAAElE,EACNO,GAAI2D,EAAEpE,EAAI,IACVU,GAAI0D,EAAElE,GACLzC,EAAQqE,WAAWyM,OAAOrS,MAC3Bf,MAASqD,EAAe9B,GAAGI,IAC1BhD,EAASoO,MAAME,KAElBvO,KAAK0H,aAAaU,KAAK,QACrBC,KAAM,QACN/G,MAAOqD,EAAe9B,GAAGI,GACzB0E,MAAO1E,EACPsF,MAAO8L,EAAaxR,GACpB2F,QAASkM,EACTvO,EAAGoE,EAAEpE,EACLE,EAAGkE,EAAElE,IAMX,IAAIzC,EAAQiR,UAAYjR,EAAQkR,SAAU,CAExC,GAAIC,IAAgB,IAAMJ,EAAgB,GAAK,IAAMA,EAAgB,GAGrE,IAAI/Q,EAAQoR,YAAcL,EAAgB5R,OAAS,EAGjD,IAAI,GADAkS,GAAKhV,EAASiK,kBAAkByK,GAC5BO,EAAI,EAAGA,EAAID,EAAGlS,OAAQmS,IAC5BH,EAAapP,KAAK,IAAMsP,EAAGC,GAAG/M,YAGhC,KAAI,GAAIgN,GAAI,EAAGA,EAAIR,EAAgB5R,OAAQoS,GAAK,EAC9CJ,EAAapP,KAAK,IAAMgP,EAAgBQ,EAAI,GAAK,IAAMR,EAAgBQ,GAI3E,IAAGvR,EAAQkR,SAAU,CAGnB,GAAIM,GAAW/R,KAAKW,IAAIX,KAAK0B,IAAInB,EAAQwR,SAAUzR,EAAOK,KAAML,EAAOoB,KAGnEsQ,EAAmBN,EAAahU,QAGhCuU,EAAoBrV,EAASmJ,aAAa7B,EAAW5D,GAASyR,GAAW,EAE7EC,GAAiBvK,OAAO,EAAG,EAAG,IAAMwK,EAAkBnP,EAAI,IAAMmP,EAAkBjP,GAClFgP,EAAiB,GAAK,IAAMV,EAAgB,GAAK,IAAMA,EAAgB,GACvEU,EAAiB1P,KAAK,IAAMgP,EAAgBA,EAAgB5R,OAAS,GAAK,IAAMuS,EAAkBjP,EAGlG,IAAIkP,GAAOlB,EAAaxR,GAAGwE,KAAK,QAC9BgD,EAAGgL,EAAiBlN,KAAK,KACxBvE,EAAQqE,WAAWsN,MAAM,GAAMlT,MAChCqD,OAAUf,EAAe9B,IACxB5C,EAASoO,MAAME,IAElBvO,MAAK0H,aAAaU,KAAK,QACrBC,KAAM,OACN3C,OAAQf,EAAe9B,GACvB8E,MAAO9E,EACP0F,MAAO8L,EAAaxR,GACpB2F,QAAS+M,IAIb,GAAG3R,EAAQiR,SAAU,CACnB,GAAIW,GAAOnB,EAAaxR,GAAGwE,KAAK,QAC9BgD,EAAG0K,EAAa5M,KAAK,KACpBvE,EAAQqE,WAAWuN,MAAM,GAAMnT,MAChCqD,OAAUf,EAAe9B,IACxB5C,EAASoO,MAAME,IAElBvO,MAAK0H,aAAaU,KAAK,QACrBC,KAAM,OACN3C,OAAQf,EAAe9B,GACvB8E,MAAO9E,EACP0F,MAAO8L,EAAaxR,GACpB2F,QAASgN,MAMjBxV,KAAK0H,aAAaU,KAAK,WACrBzE,OAAQA,EACR4D,UAAWA,EACXrF,IAAKlC,KAAKkC,IACV0B,QAASA,IAgJb,QAAS6R,GAAK9T,EAAOgB,EAAMiB,EAAS0F,GAClCrJ,EAASwV,KAAKxJ,MAAMF,YAAY/K,KAAKhB,KACnC2B,EACAgB,EACA1C,EAASS,UAAWgV,EAAgB9R,GACpC0F,GAhVJ,GAAIoM,IACFxR,OACEC,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,MAElCmF,OACErB,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,KAChCoF,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACR6R,UAAU,EACVD,WAAW,EACXE,UAAU,EACVM,SAAU,EACVJ,YAAY,EACZvQ,IAAKzB,OACLsB,KAAMtB,OACNiB,aAAc,EACdgE,YACEqM,MAAO,gBACPzL,MAAO,WACP0L,WAAY,YACZzR,OAAQ,YACR0S,KAAM,UACNd,MAAO,WACPa,KAAM,UACN/N,KAAM,UACNgN,UAAW,WACXrL,SAAU,cACVjB,WAAY,iBAyShBjI,GAASwV,KAAOxV,EAASqN,KAAK5M,QAC5BqL,YAAa0J,EACbzI,YAAaA,KAGf7M,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA2CA,SAAS+M,GAAYpJ,GACnB,GACED,GADE0Q,KAEF1P,EAAiB1E,EAASiD,mBAAmBjD,EAASyC,aAAa1C,KAAK2C,MAAO3C,KAAK2C,KAAK8E,OAAO1E,OAGlG/C,MAAKkC,IAAMjC,EAAS4B,UAAU7B,KAAK8B,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQqE,WAAWqM,OAGhG3Q,EAAS1D,EAASyE,UAAU1E,KAAKkC,IAAKyC,EAAgBf,EAAS,EAE/D,IAAI2D,GAAYtH,EAASsG,gBAAgBvG,KAAKkC,IAAK0B,GAE/C6D,EAASzH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWsM,YAC1D/M,EAAOxH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWuM,WAEtDmB,EAAY1V,EAASmJ,aAAa7B,EAAW5D,GAAS,GAAI,EAE5D1D,GAASqH,YAAYC,EAAWvH,KAAK2C,KAAM6E,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,uBAC1FjH,EAASiJ,YAAY3B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAI7C,KAAK2C,KAAKG,OAAOC,OAAQF,IAAK,CAEhD,GAAI+S,GAAQ/S,GAAK7C,KAAK2C,KAAKG,OAAOC,OAAS,GAAK,EAE9C8S,EAAkBtO,EAAUxF,QAAU4C,EAAe9B,GAAGE,OAAS,CAEnEsR,GAAaxR,GAAK7C,KAAKkC,IAAImF,KAAK,KAG7BrH,KAAK2C,KAAKG,OAAOD,GAAGkL,MACrBsG,EAAaxR,GAAGR,MACdoS,cAAezU,KAAK2C,KAAKG,OAAOD,GAAGkL,MAClC9N,EAASoO,MAAME,KAIpB8F,EAAaxR,GAAGP,UACdsB,EAAQqE,WAAWnF,OAClB9C,KAAK2C,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQqE,WAAWnF,OAAS,IAAM7C,EAASM,cAAcsC,IAC3FsF,KAAK,KAEP,KAAI,GAAIlF,GAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAAK,CAChD,GACE6S,GADEvL,EAAItK,EAASmJ,aAAa7B,EAAW5D,EAAQgB,EAAe9B,GAAII,EAKpEsH,GAAEpE,GAAK0P,EAAmBD,EAAQhS,EAAQmS,kBAE1CD,EAAMzB,EAAaxR,GAAGwE,KAAK,QACzBX,GAAI6D,EAAEpE,EACNQ,GAAIgP,EAAUtP,EACdO,GAAI2D,EAAEpE,EACNU,GAAI0D,EAAElE,GACLzC,EAAQqE,WAAW6N,KAAKzT,MACzBf,MAASqD,EAAe9B,GAAGI,IAC1BhD,EAASoO,MAAME,KAElBvO,KAAK0H,aAAaU,KAAK,QACrBC,KAAM,MACN/G,MAAOqD,EAAe9B,GAAGI,GACzB0E,MAAO1E,EACPsF,MAAO8L,EAAaxR,GACpB2F,QAASsN,EACTpP,GAAI6D,EAAEpE,EACNQ,GAAIgP,EAAUtP,EACdO,GAAI2D,EAAEpE,EACNU,GAAI0D,EAAElE,KAKZrG,KAAK0H,aAAaU,KAAK,WACrBzE,OAAQA,EACR4D,UAAWA,EACXrF,IAAKlC,KAAKkC,IACV0B,QAASA,IAwGb,QAASoS,GAAIrU,EAAOgB,EAAMiB,EAAS0F,GACjCrJ,EAAS+V,IAAI/J,MAAMF,YAAY/K,KAAKhB,KAClC2B,EACAgB,EACA1C,EAASS,UAAWgV,EAAgB9R,GACpC0F,GArOJ,GAAIoM,IACFxR,OACEC,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,MAElCmF,OACErB,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,KAChCoF,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRsB,KAAMtB,OACNyB,IAAKzB,OACLiB,aAAc,EACd8R,kBAAmB,GACnB9N,YACEqM,MAAO,eACPzL,MAAO,WACP0L,WAAY,YACZzR,OAAQ,YACRgT,IAAK,SACLtO,KAAM,UACNgN,UAAW,WACXrL,SAAU,cACVjB,WAAY,iBAoMhBjI,GAAS+V,IAAM/V,EAASqN,KAAK5M,QAC3BqL,YAAaiK,EACbhJ,YAAaA,KAGf7M,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAwBA,SAASgW,GAAwBC,EAAQrN,EAAOsN,GAC9C,GAAIC,GAAavN,EAAM1C,EAAI+P,EAAO/P,CAElC,OAAGiQ,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SAIX,QAASnJ,GAAYpJ,GACnB,GACE2D,GACAxB,EACAsQ,EACAC,EAJEjC,KAKFkC,EAAa3S,EAAQ2S,WACrBpT,EAAYlD,EAASyC,aAAa1C,KAAK2C,KAGzC3C,MAAKkC,IAAMjC,EAAS4B,UAAU7B,KAAK8B,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQqE,WAAWqM,OAEhG/M,EAAYtH,EAASsG,gBAAgBvG,KAAKkC,IAAK0B,EAAS,EAAG,GAE3DmC,EAAS1C,KAAK0B,IAAIwC,EAAUxF,QAAU,EAAGwF,EAAUvF,SAAW,GAE9DsU,EAAe1S,EAAQ4S,OAASrT,EAAUsT,OAAO,SAASC,EAAeC,GACvE,MAAOD,GAAgBC,GACtB,GAKH5Q,GAAUnC,EAAQgT,MAAQhT,EAAQiT,WAAa,EAAK,EAIpDR,EAAczS,EAAQgT,MAAQ7Q,EAASA,EAAS,EAEhDsQ,GAAezS,EAAQ+E,WAevB,KAAK,GAZDuN,IACF/P,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAU,EACtCsE,EAAGkB,EAAUV,GAAKU,EAAUvF,SAAW,GAIrC8U,EAEU,IAFa9W,KAAK2C,KAAKG,OAAO0N,OAAO,SAASuG,GAC1D,MAAe,KAARA,IACNhU,OAIMF,EAAI,EAAGA,EAAI7C,KAAK2C,KAAKG,OAAOC,OAAQF,IAAK,CAChDwR,EAAaxR,GAAK7C,KAAKkC,IAAImF,KAAK,IAAK,KAAM,MAAM,GAG9CrH,KAAK2C,KAAKG,OAAOD,GAAGkL,MACrBsG,EAAaxR,GAAGR,MACdoS,cAAezU,KAAK2C,KAAKG,OAAOD,GAAGkL,MAClC9N,EAASoO,MAAME,KAIpB8F,EAAaxR,GAAGP,UACdsB,EAAQqE,WAAWnF,OAClB9C,KAAK2C,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQqE,WAAWnF,OAAS,IAAM7C,EAASM,cAAcsC,IAC3FsF,KAAK,KAEP,IAAI6O,GAAWT,EAAapT,EAAUN,GAAKyT,EAAe,GAGvDU,GAAWT,IAAe,MAC3BS,GAAY,IAGd,IAAIC,GAAQhX,EAAS2F,iBAAiBsQ,EAAO/P,EAAG+P,EAAO7P,EAAGN,EAAQwQ,GAAoB,IAAN1T,GAAWiU,EAAuB,EAAI,KACpHI,EAAMjX,EAAS2F,iBAAiBsQ,EAAO/P,EAAG+P,EAAO7P,EAAGN,EAAQiR,GAC5DG,EAAoC,KAAzBH,EAAWT,EAAoB,IAAM,IAChDlM,GAEE,IAAK6M,EAAI/Q,EAAG+Q,EAAI7Q,EAEhB,IAAKN,EAAQA,EAAQ,EAAGoR,EAAU,EAAGF,EAAM9Q,EAAG8Q,EAAM5Q,EAIrDzC,GAAQgT,SAAU,GACnBvM,EAAE1E,KAAK,IAAKuQ,EAAO/P,EAAG+P,EAAO7P,EAK/B,IAAI+Q,GAAO/C,EAAaxR,GAAGwE,KAAK,QAC9BgD,EAAGA,EAAElC,KAAK,MACTvE,EAAQqE,WAAWlH,OAAS6C,EAAQgT,MAAQ,IAAMhT,EAAQqE,WAAW2O,MAAQ,IA6BhF,IA1BAQ,EAAK/U,MACHf,MAAS6B,EAAUN,IAClB5C,EAASoO,MAAME,KAGf3K,EAAQgT,SAAU,GACnBQ,EAAK/U,MACHE,MAAS,mBAAqBqB,EAAQiT,WAAc,OAKxD7W,KAAK0H,aAAaU,KAAK,QACrBC,KAAM,QACN/G,MAAO6B,EAAUN,GACjByT,aAAcA,EACd3O,MAAO9E,EACP0F,MAAO8L,EAAaxR,GACpB2F,QAAS4O,EACTlB,OAAQA,EACRnQ,OAAQA,EACRwQ,WAAYA,EACZS,SAAUA,IAITpT,EAAQ6E,UAAW,CAEpB,GAAIC,GAAgBzI,EAAS2F,iBAAiBsQ,EAAO/P,EAAG+P,EAAO7P,EAAGgQ,EAAaE,GAAcS,EAAWT,GAAc,GACpH3O,EAAoBhE,EAAQiE,sBAAsB7H,KAAK2C,KAAK8E,OAASzH,KAAK2C,KAAK8E,OAAO5E,GAAKM,EAAUN,GAAIA,GAEvG+F,EAAeyL,EAAaxR,GAAGwE,KAAK,QACtCgQ,GAAI3O,EAAcvC,EAClBmR,GAAI5O,EAAcrC,EAClBkR,cAAetB,EAAwBC,EAAQxN,EAAe9E,EAAQ4T,iBACrE5T,EAAQqE,WAAWY,OAAO7B,KAAK,GAAKY,EAGvC5H,MAAK0H,aAAaU,KAAK,QACrBC,KAAM,QACNV,MAAO9E,EACP0F,MAAO8L,EAAaxR,GACpB2F,QAASI,EACT5B,KAAM,GAAKY,EACXzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,IAMrBkQ,EAAaS,EAGfhX,KAAK0H,aAAaU,KAAK,WACrBb,UAAWA,EACXrF,IAAKlC,KAAKkC,IACV0B,QAASA,IAoFb,QAAS6T,GAAI9V,EAAOgB,EAAMiB,EAAS0F,GACjCrJ,EAASwX,IAAIxL,MAAMF,YAAY/K,KAAKhB,KAClC2B,EACAgB,EACA1C,EAASS,UAAWgV,EAAgB9R,GACpC0F,GA/QJ,GAAIoM,IACF3T,MAAOiB,OACPhB,OAAQgB,OACRiB,aAAc,EACdgE,YACEqM,MAAO,eACPxR,OAAQ,YACR/B,MAAO,WACP6V,MAAO,WACP/N,MAAO,YAET0N,WAAY,EACZC,MAAOxT,OACP4T,OAAO,EACPC,WAAY,GACZpO,WAAW,EACXE,YAAa,EACbd,sBAAuB5H,EAASI,KAChCqX,eAAe,EACfF,eAAgB,UAgQlBvX,GAASwX,IAAMxX,EAASqN,KAAK5M,QAC3BqL,YAAa0L,EACbzK,YAAaA,EACbiJ,wBAAyBA,KAG3B9V,OAAQC,SAAUH,GAEbA","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.3\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.3'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index 1eedabb9..e8ad6637 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.4.2", + "version": "0.4.3", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index 6a52a8d8..b5aecfcf 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.4.2' + version: '0.4.3' }; (function (window, document, Chartist) { From f1acd2ca1397a1f95b523bd444cc9b4d9f55977f Mon Sep 17 00:00:00 2001 From: Riccardo Forina Date: Thu, 27 Nov 2014 12:56:23 +0100 Subject: [PATCH 115/593] Update index.yml Fixed Andorid typo --- site/data/pages/index.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 9617e3bd..c03040f3 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -22,8 +22,8 @@ sections: - Chrome 35 - Safari 7 - Safari 8 - - Andorid 4.3 - - Andorid 4.4 + - Android 4.3 + - Android 4.4 - iOS Safari 6 - iOS Safari 7 features: @@ -50,10 +50,10 @@ sections: - name: Safari 8 status: supported text: Supported - - name: Andorid 4.3 + - name: Android 4.3 status: supported text: Supported - - name: Andorid 4.4 + - name: Android 4.4 status: supported text: Supported - name: iOS Safari 6 @@ -85,10 +85,10 @@ sections: - name: Safari 8 status: supported text: Supported - - name: Andorid 4.3 + - name: Android 4.3 status: not-supported text: Not supported - - name: Andorid 4.4 + - name: Android 4.4 status: supported text: Supported - name: iOS Safari 6 @@ -120,10 +120,10 @@ sections: - name: Safari 8 status: supported text: Supported - - name: Andorid 4.3 + - name: Android 4.3 status: not-supported text: Not supported - - name: Andorid 4.4 + - name: Android 4.4 status: supported text: Supported - name: iOS Safari 6 @@ -155,10 +155,10 @@ sections: - name: Safari 8 status: supported text: Supported - - name: Andorid 4.3 + - name: Android 4.3 status: supported text: Supported - - name: Andorid 4.4 + - name: Android 4.4 status: supported text: Supported - name: iOS Safari 6 @@ -190,10 +190,10 @@ sections: - name: Safari 8 status: supported text: Supported - - name: Andorid 4.3 + - name: Android 4.3 status: supported text: Supported - - name: Andorid 4.4 + - name: Android 4.4 status: supported text: Supported - name: iOS Safari 6 From 93576412097ac0d13a68fb2cc7607c24620b6085 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 19:18:40 +0100 Subject: [PATCH 116/593] Bug fixed in FF tooltip example positioning with clientX / clientY, fixes #95 --- site/examples/behavior-with-jquery.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/examples/behavior-with-jquery.js b/site/examples/behavior-with-jquery.js index a79cafcb..4f72957b 100644 --- a/site/examples/behavior-with-jquery.js +++ b/site/examples/behavior-with-jquery.js @@ -41,7 +41,7 @@ $chart.on('mouseleave', '.ct-point', function() { $chart.on('mousemove', function(event) { $toolTip.css({ - left: event.offsetX - $toolTip.width() / 2 - 10, - top: event.offsetY - $toolTip.height() - 40 + left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, + top: (event.offsetY || event.originalEvent.layerY) - $toolTip.height() - 40 }); -}); \ No newline at end of file +}); From 426c3b5b55f778a3696c2edbba815da09a52a29f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 27 Nov 2014 19:19:27 +0100 Subject: [PATCH 117/593] Bug fixed on SVG container for chartist guy on documentation index causing issues when scaled down --- site/styles/_landing.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/styles/_landing.scss b/site/styles/_landing.scss index 79ec077d..3c5d5f98 100644 --- a/site/styles/_landing.scss +++ b/site/styles/_landing.scss @@ -34,6 +34,7 @@ > figure { @include ct-responsive-svg-container($ratio: (1/1)); + width: auto; > svg { width: 100%; @@ -169,4 +170,4 @@ @include icon($fa-var-exclamation-circle, $icon-location: after); } } -} \ No newline at end of file +} From 51553dc5dfe7016fd451d674edc7f2f8cbf493a1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 28 Nov 2014 14:55:46 +0100 Subject: [PATCH 118/593] Fixed some doc site style issues on landing page --- site/styles/_landing.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/styles/_landing.scss b/site/styles/_landing.scss index 3c5d5f98..8a1a1269 100644 --- a/site/styles/_landing.scss +++ b/site/styles/_landing.scss @@ -33,8 +33,8 @@ margin: 0 auto; > figure { + margin: 0; @include ct-responsive-svg-container($ratio: (1/1)); - width: auto; > svg { width: 100%; From 4e1331fc38b0ee7c663cec81147ae13dea57cf15 Mon Sep 17 00:00:00 2001 From: Kenny Date: Mon, 8 Dec 2014 16:16:30 +0000 Subject: [PATCH 119/593] Fixed typos on examples page --- site/data/pages/examples.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 3fdb6a7c..7fd066ff 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -38,7 +38,7 @@ sections: intro: > This chart uses the showArea option to draw line, dots but also an area shape. Use the low option to specify a fixed lower bound that will make the area expand. You can also use the areaBase property - to specify a data value that will be used to determine the area shap base position (this is 0 by default). + to specify a data value that will be used to determine the area shape base position (this is 0 by default). - type: live-example data: title: Bi-polar Line chart with area only @@ -90,16 +90,16 @@ sections: classes: ct-golden-section intro: > This example makes use of label interpolation and the seriesBarDistance property that allows you - to make bars overlap over each other. This then can be used to use the avialable space on mobile better. + to make bars overlap over each other. This then can be used to use the available space on mobile better. Resize your browser to see the effect of the responsive configuration. - type: live-example data: - title: Add peek cricles using the draw events + title: Add peak circles using the draw events level: 4 id: example-bar-with-circle-modify-drawing classes: ct-golden-section intro: > - With the help of draw events we are able to add a custom SVG shape to the peek of our bars. + With the help of draw events we are able to add a custom SVG shape to the peak of our bars. - type: live-example data: title: Multi-line labels From 6319cda12c69331131cf7d5b46ef887b41ad44a1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 11 Dec 2014 23:02:35 +0100 Subject: [PATCH 120/593] Handling error gracefully when ElementTimeControl is not supported on SMIL animation node, fixes #102 --- site/examples/example-line-svg-animation.js | 4 ++-- src/scripts/svg.js | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/site/examples/example-line-svg-animation.js b/site/examples/example-line-svg-animation.js index 0e344de6..7ffe6e02 100644 --- a/site/examples/example-line-svg-animation.js +++ b/site/examples/example-line-svg-animation.js @@ -46,7 +46,7 @@ chart.on('draw', function(data) { from: data.y + 100, to: data.y, // We can specify an easing function from Chartist.Svg.Easing - easing: 'easeInOutBack' + easing: 'easeOutQuart' } }); } else if(data.type === 'label' && data.axis === 'y') { @@ -56,7 +56,7 @@ chart.on('draw', function(data) { dur: durations, from: data.x - 100, to: data.x, - easing: 'easeInOutBack' + easing: 'easeOutQuart' } }); } else if(data.type === 'point') { diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 2e598af5..0eb5c413 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -422,8 +422,19 @@ if(guided) { // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout setTimeout(function() { - animate._node.beginElement(); - }, timeout); + // If beginElement fails we set the animated attribute to the end position and remove the animate element + // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in + // the browser. (Currently FF 34 does not support animate elements in foreignObjects) + try { + animate._node.beginElement(); + } catch(err) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this), timeout); } if(eventEmitter) { From 7d2269296cc113d0af427e9ff65412cfdc3ceb5b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 11 Dec 2014 23:18:40 +0100 Subject: [PATCH 121/593] Added better documentation for Pie chart object series notation, fixes #105 --- src/scripts/charts/pie.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index e474f141..32b29905 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -198,7 +198,7 @@ * * @memberof Chartist.Pie * @param {String|Node} query A selector query string or directly a DOM element - * @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. + * @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 objects that contain a data property with the value and a className property to override the CSS class name for the series group. * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] * @return {Object} An object with a version and an update method to manually redraw the chart @@ -272,6 +272,21 @@ * labelOffset: 50, * labelDirection: 'explode' * }); + * + * @example + * // Overriding the class names for individual series + * new Chartist.Pie('.ct-chart', { + * series: [{ + * data: 20, + * className: 'my-custom-class-one' + * }, { + * data: 10, + * className: 'my-custom-class-two' + * }, { + * data: 70, + * className: 'my-custom-class-three' + * }] + * }); */ function Pie(query, data, options, responsiveOptions) { Chartist.Pie.super.constructor.call(this, From 99fe27ba5b8ec083fc76d36b176278a166f40ab1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 11 Dec 2014 23:37:03 +0100 Subject: [PATCH 122/593] Fixed test paths --- tasks/jasmine.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tasks/jasmine.js b/tasks/jasmine.js index 2e9770af..1d467673 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -13,14 +13,14 @@ module.exports = function (grunt) { return { dist: { src: [ - '<%= pkg.config.src %>/core.js', - '<%= pkg.config.src %>/event.js', - '<%= pkg.config.src %>/class.js', - '<%= pkg.config.src %>/base.js', - '<%= pkg.config.src %>/svg.js', - '<%= pkg.config.src %>/types/line.js', - '<%= pkg.config.src %>/types/bar.js', - '<%= pkg.config.src %>/types/pie.js' + '<%= pkg.config.src %>/scripts/core.js', + '<%= pkg.config.src %>/scripts/event.js', + '<%= pkg.config.src %>/scripts/class.js', + '<%= pkg.config.src %>/scripts/base.js', + '<%= pkg.config.src %>/scripts/svg.js', + '<%= pkg.config.src %>/scripts/charts/line.js', + '<%= pkg.config.src %>/scripts/charts/bar.js', + '<%= pkg.config.src %>/scripts/charts/pie.js' ], options: { specs: '<%= pkg.config.test %>/spec/**/spec-*.js', From 94315f1ec1595cbc1620ab4cb5d37e6434a75498 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 11 Dec 2014 23:38:22 +0100 Subject: [PATCH 123/593] Using parent() instead of node.parentNode for consistency and to prevent errors --- src/scripts/svg.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 0eb5c413..2f3c556b 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -215,7 +215,7 @@ */ function remove() { this._node.parentNode.removeChild(this._node); - return new Chartist.Svg(this._node.parentNode); + return this.parent(); } /** From 69859f26fd9005a87930e5a7db23c58803d42e9d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 11 Dec 2014 23:40:39 +0100 Subject: [PATCH 124/593] Update to 0.4.4 --- CHANGELOG.md | 5 +++++ bower.json | 2 +- dist/chartist.js | 38 ++++++++++++++++++++++++++++++++------ dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 ++-- dist/chartist.min.js.map | 2 +- package.json | 2 +- src/scripts/core.js | 2 +- 8 files changed, 44 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae67e8c3..69a0545d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ +v0.4.4 - 11 Dec 2014 +-------------------- +- Fixed NS_ERROR_FAILURE error in Firefox and added graceful handling of unsupported SMIL animations (i.e. in foreignObjects) + v0.4.3 - 27 Nov 2014 +-------------------- - Updated plugin architecture for convenience reasons and better support for modularization v0.4.2 - 27 Nov 2014 diff --git a/bower.json b/bower.json index 5080da90..875cb461 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.4.3", + "version": "0.4.4", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 306beb4a..ff968147 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { - /* Chartist.js 0.4.3 + /* Chartist.js 0.4.4 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.4.3' + version: '0.4.4' }; (function (window, document, Chartist) { @@ -1360,7 +1360,7 @@ */ function remove() { this._node.parentNode.removeChild(this._node); - return new Chartist.Svg(this._node.parentNode); + return this.parent(); } /** @@ -1567,8 +1567,19 @@ if(guided) { // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout setTimeout(function() { - animate._node.beginElement(); - }, timeout); + // If beginElement fails we set the animated attribute to the end position and remove the animate element + // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in + // the browser. (Currently FF 34 does not support animate elements in foreignObjects) + try { + animate._node.beginElement(); + } catch(err) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this), timeout); } if(eventEmitter) { @@ -2530,7 +2541,7 @@ * * @memberof Chartist.Pie * @param {String|Node} query A selector query string or directly a DOM element - * @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. + * @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 objects that contain a data property with the value and a className property to override the CSS class name for the series group. * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] * @return {Object} An object with a version and an update method to manually redraw the chart @@ -2604,6 +2615,21 @@ * labelOffset: 50, * labelDirection: 'explode' * }); + * + * @example + * // Overriding the class names for individual series + * new Chartist.Pie('.ct-chart', { + * series: [{ + * data: 20, + * className: 'my-custom-class-one' + * }, { + * data: 10, + * className: 'my-custom-class-two' + * }, { + * data: 70, + * className: 'my-custom-class-three' + * }] + * }); */ function Pie(query, data, options, responsiveOptions) { Chartist.Pie.super.constructor.call(this, diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 3049590a..75a118cc 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.4.3 +/* Chartist.js 0.4.4 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 37933874..4d909fb0 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.4.3 +/* Chartist.js 0.4.4 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.4"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index c715d8af..f9e5676c 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","plugins","plugin","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","params","to","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.3\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.3'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 new Chartist.Svg(this._node.parentNode);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 animate._node.beginElement();\n }, 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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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.\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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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 function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","plugins","plugin","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.4\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.4'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index e8ad6637..c33093c1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.4.3", + "version": "0.4.4", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index b5aecfcf..3e7dc25c 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.4.3' + version: '0.4.4' }; (function (window, document, Chartist) { From f5edb2240dd89568ba19b79439153b973ce76ad5 Mon Sep 17 00:00:00 2001 From: Deck Pope Date: Fri, 12 Dec 2014 14:05:29 +0200 Subject: [PATCH 125/593] change the order between area and line this way, you can have a stroke for area and also you can see the line above area. in the current version, when you have both strokes the area it overrides the line. which is not good for styling --- dist/chartist.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/dist/chartist.js b/dist/chartist.js index ff968147..7367cc30 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -1880,7 +1880,23 @@ pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); } } + + if(options.showLine) { + var line = seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: line + }); + } + if(options.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. @@ -1911,22 +1927,6 @@ element: area }); } - - if(options.showLine) { - var line = seriesGroups[i].elem('path', { - d: pathElements.join('') - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[i], - index: i, - group: seriesGroups[i], - element: line - }); - } } } From b6f0fb0362b9ccb5009f545df653ee737b8672dc Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 13 Dec 2014 15:00:30 +0100 Subject: [PATCH 126/593] Added functionality to make use of full chart width on line and bar chart, fixes #18 --- site/examples/bi-polar-bar-interpolated.js | 6 +- site/examples/example-bipolar-line-area.js | 3 +- src/scripts/charts/bar.js | 107 +++++++------------- src/scripts/charts/line.js | 112 +++++++-------------- src/scripts/charts/pie.js | 66 ++++++------ src/scripts/core.js | 7 +- 6 files changed, 115 insertions(+), 186 deletions(-) diff --git a/site/examples/bi-polar-bar-interpolated.js b/site/examples/bi-polar-bar-interpolated.js index e9c1da8e..50fcd752 100644 --- a/site/examples/bi-polar-bar-interpolated.js +++ b/site/examples/bi-polar-bar-interpolated.js @@ -12,7 +12,9 @@ var options = { labelInterpolationFnc: function(value, index) { return index % 2 === 0 ? value : null; } - } + }, + fullWidth: true, + centerBars: false }; -new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file +new Chartist.Bar('.ct-chart', data, options); diff --git a/site/examples/example-bipolar-line-area.js b/site/examples/example-bipolar-line-area.js index 03cd06fc..213e6cf7 100644 --- a/site/examples/example-bipolar-line-area.js +++ b/site/examples/example-bipolar-line-area.js @@ -12,8 +12,9 @@ new Chartist.Line('.ct-chart', { showArea: true, showLine: false, showPoint: false, + fullWidth: true, axisX: { showLabel: false, showGrid: false } -}); \ No newline at end of file +}); diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 071ec7ba..69c88e16 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -7,34 +7,63 @@ (function(window, document, Chartist){ 'use strict'; + /** + * Default options in bar charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Bar + */ var defaultOptions = { + // Options for X-Axis axisX: { + // The offset of the chart drawing area to the border of the container offset: 30, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop }, + // Options for Y-Axis axisY: { + // The offset of the chart drawing area to the border of the container offset: 40, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20 }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Padding of the chart drawing area to the container element and labels chartPadding: 5, + // Specify the distance in pixel of bars in a group seriesBarDistance: 15, + // 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. For bar charts this might be used in conjunction with the centerBars property set to false. + fullWidth: false, + // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property. + centerBars: true, + // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', label: 'ct-label', @@ -48,6 +77,10 @@ } }; + /** + * Creates a new chart + * + */ function createChart(options) { var seriesGroups = [], bounds, @@ -64,7 +97,7 @@ var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), grid = this.svg.elem('g').addClass(options.classNames.gridGroup), // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); + zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options); Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); @@ -74,8 +107,8 @@ for (var i = 0; i < this.data.series.length; i++) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. var biPol = i - (this.data.series.length - 1) / 2, - // Half of the period with between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; + // Half of the period width between vertical grid lines used to position bars + periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2; seriesGroups[i] = this.svg.elem('g'); @@ -93,12 +126,11 @@ ].join(' ')); for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), + var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options), bar; // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors - p.x += periodHalfWidth + (biPol * options.seriesBarDistance); + p.x += (options.centerBars ? periodHalfWidth : 0) + (biPol * options.seriesBarDistance); bar = seriesGroups[i].elem('line', { x1: p.x, @@ -142,69 +174,6 @@ * @return {Object} An object which exposes the API for the created chart * * @example - * // These are the default options of the bar chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the chart drawing area to the border of the container - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the chart drawing area to the border of the container - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Specify the distance in pixel of bars in a group - * seriesBarDistance: 15, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-bar', - * label: 'ct-label', - * labelGroup: 'ct-labels', - * series: 'ct-series', - * bar: 'ct-bar', - * grid: 'ct-grid', - * gridGroup: 'ct-grids', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example * // Create a simple bar chart * var data = { * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index c06e1afe..04abf214 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -9,38 +9,69 @@ (function(window, document, Chartist){ 'use strict'; + /** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Line + */ var defaultOptions = { + // Options for X-Axis axisX: { + // The offset of the labels to the chart area offset: 30, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop }, + // Options for Y-Axis axisY: { + // The offset of the labels to the chart area offset: 40, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20 }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, + // If the line should be drawn or not showLine: true, + // If dots should be drawn or not showPoint: true, + // If the line chart should draw an area showArea: false, + // The base for the area chart that will be used to close the area shape (is normally 0) areaBase: 0, + // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) lineSmooth: true, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, + // Padding of the chart drawing area to the container element and labels chartPadding: 5, + // 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. + fullWidth: false, + // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-line', label: 'ct-label', @@ -56,6 +87,10 @@ } }; + /** + * Creates a new chart + * + */ function createChart(options) { var seriesGroups = [], bounds, @@ -98,7 +133,7 @@ point; for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); + p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options); pathCoordinates.push(p.x, p.y); //If we should show points we need to create them now to avoid secondary loop @@ -152,7 +187,7 @@ var areaPathElements = pathElements.slice(); // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options); // And splice our new area path array to add the missing path elements to close the area shape areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; @@ -211,79 +246,6 @@ * @return {Object} An object which exposes the API for the created chart * * @example - * // These are the default options of the line chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the labels to the chart area - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the labels to the chart area - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // If the line should be drawn or not - * showLine: true, - * // If dots should be drawn or not - * showPoint: true, - * // If the line chart should draw an area - * showArea: false, - * // The base for the area chart that will be used to close the area shape (is normally 0) - * areaBase: 0, - * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) - * lineSmooth: true, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * 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', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example * // Create a simple line chart * var data = { * // A labels array that can contain any sort of values diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 32b29905..60cb3a7c 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -7,10 +7,19 @@ (function(window, document, Chartist) { 'use strict'; + /** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Pie + */ var defaultOptions = { + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, + // Padding of the chart drawing area to the container element and labels chartPadding: 5, + // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-pie', series: 'ct-series', @@ -18,17 +27,32 @@ donut: 'ct-donut', label: 'ct-label' }, + // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. startAngle: 0, + // 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. total: undefined, + // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. donut: false, + // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. donutWidth: 60, + // If a label should be shown or not showLabel: true, + // 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. labelOffset: 0, + // An interpolation function for the label value labelInterpolationFnc: Chartist.noop, - labelOverflow: false, + // 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. labelDirection: 'neutral' }; + /** + * Determines SVG anchor position based on direction and center parameter + * + * @param center + * @param label + * @param direction + * @returns {string} + */ function determineAnchorPosition(center, label, direction) { var toTheRight = label.x > center.x; @@ -43,6 +67,11 @@ } } + /** + * Creates the pie chart + * + * @param options + */ function createChart(options) { var seriesGroups = [], chartRect, @@ -204,41 +233,6 @@ * @return {Object} An object with a version and an update method to manually redraw the chart * * @example - * // Default options of the pie chart - * var defaultOptions = { - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-pie', - * series: 'ct-series', - * slice: 'ct-slice', - * donut: 'ct-donut', - label: 'ct-label' - * }, - * // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. - * startAngle: 0, - * // 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. - * total: undefined, - * // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. - * donut: false, - * // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. - * donutWidth: 60, - * // If a label should be shown or not - * showLabel: true, - * // 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. - * labelOffset: 0, - * // An interpolation function for the label value - * labelInterpolationFnc: function(value, index) {return value;}, - * // 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. - * labelDirection: 'neutral' - * }; - * - * @example * // Simple pie chart example with four series * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] diff --git a/src/scripts/core.js b/src/scripts/core.js index 3e7dc25c..d9fc6a43 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -421,7 +421,7 @@ var Chartist = { // Create X-Axis data.labels.forEach(function (value, index) { var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - width = chartRect.width() / data.labels.length, + width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)), height = options.axisX.offset, pos = chartRect.x1 + width * index; @@ -577,11 +577,12 @@ var Chartist = { * @param {Object} bounds All the values to set the bounds of the chart * @param {Array} data The array that contains the data to be visualized in the chart * @param {Number} index The index of the current project point + * @param {Object} options The chart options that are used to influence the calculations * @return {Object} The coordinates object of the current project point containing an x and y number property */ - Chartist.projectPoint = function (chartRect, bounds, data, index) { + Chartist.projectPoint = function (chartRect, bounds, data, index, options) { return { - x: chartRect.x1 + chartRect.width() / data.length * index, + x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index, y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) }; }; From 86d02114591aa87f27a9d7bfde1918078b5ed344 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 14 Dec 2014 03:29:38 +0100 Subject: [PATCH 127/593] Modified live example template to allow markup in intro --- site/partials/live-example.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/partials/live-example.hbs b/site/partials/live-example.hbs index 09f4af29..73062e28 100644 --- a/site/partials/live-example.hbs +++ b/site/partials/live-example.hbs @@ -8,7 +8,7 @@ - \ No newline at end of file + From 879450807af8ca37b8ef44b378aa35011d2f4bfe Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 14 Dec 2014 03:32:50 +0100 Subject: [PATCH 128/593] Added new option to switch bar chart into stacked mode and refactored core functions, fixes #23 --- src/scripts/charts/bar.js | 51 +++++++++++++++++++++++++------- src/scripts/charts/line.js | 2 +- src/scripts/core.js | 60 ++++++++++++++++++++++++++++++++++---- 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 69c88e16..71e03249 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -63,6 +63,8 @@ fullWidth: false, // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property. centerBars: true, + // If set to true this property will cause the series bars to be stacked and 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. + stackBars: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', @@ -84,20 +86,34 @@ function createChart(options) { var seriesGroups = [], bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length), + highLow; // Create new svg element this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + if(options.stackBars) { + // If stacked bars we need to calculate the high low from stacked values from each series + var serialSums = Chartist.serialMap(normalizedData, function serialSums() { + return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); + }); + + highLow = Chartist.getHighLow([serialSums]); + } else { + highLow = Chartist.getHighLow(normalizedData); + } + // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); + bounds = Chartist.getBounds(this.svg, highLow, options, 0); var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), grid = this.svg.elem('g').addClass(options.classNames.gridGroup), - // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options); + // Projected 0 point + zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options), + // Used to track the screen coordinates of stacked bars + stackedBarValues = []; Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); @@ -127,16 +143,29 @@ for(var j = 0; j < normalizedData[i].length; j++) { var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options), - bar; + bar, + previousStack, + y1, + y2; + + // Offset to center bar between grid lines + p.x += (options.centerBars ? periodHalfWidth : 0); + // Using bi-polar offset for multiple series if no stacked bars are used + p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance; + + // Enter value in stacked bar values used to remember previous screen value for stacking up bars + previousStack = stackedBarValues[j] || zeroPoint.y; + stackedBarValues[j] = previousStack - (zeroPoint.y - p.y); - // Offset to center bar between grid lines and using bi-polar offset for multiple series - p.x += (options.centerBars ? periodHalfWidth : 0) + (biPol * options.seriesBarDistance); + // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line + y1 = options.stackBars ? previousStack : zeroPoint.y; + y2 = options.stackBars ? stackedBarValues[j] : p.y; bar = seriesGroups[i].elem('line', { x1: p.x, - y1: zeroPoint.y, + y1: y1, x2: p.x, - y2: p.y + y2: y2 }, options.classNames.bar).attr({ 'value': normalizedData[i][j] }, Chartist.xmlNs.uri); @@ -148,9 +177,9 @@ group: seriesGroups[i], element: bar, x1: p.x, - y1: zeroPoint.y, + y1: y1, x2: p.x, - y2: p.y + y2: y2 }); } } diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 04abf214..40b49b7c 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -100,7 +100,7 @@ this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options); + bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options); var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing diff --git a/src/scripts/core.js b/src/scripts/core.js index d9fc6a43..6770fc2b 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -100,6 +100,54 @@ var Chartist = { return query instanceof Node ? query : document.querySelector(query); }; + /** + * Functional style helper to produce array with given length initialized with undefined values + * + * @memberof Chartist.Core + * @param length + * @returns {Array} + */ + Chartist.times = function(length) { + return Array.apply(null, new Array(length)); + }; + + /** + * Sum helper to be used in reduce functions + * + * @memberof Chartist.Core + * @param previous + * @param current + * @returns {*} + */ + Chartist.sum = function(previous, current) { + return previous + current; + }; + + /** + * 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). + * + * @memberof Chartist.Core + * @param arr + * @param cb + * @returns {Array} + */ + Chartist.serialMap = function(arr, cb) { + var result = [], + length = Math.max.apply(null, arr.map(function(e) { + return e.length; + })); + + Chartist.times(length).forEach(function(e, index) { + var args = arr.map(function(e) { + return e[index]; + }); + + result[index] = cb.apply(null, args); + }); + + return result; + }; + /** * Create or reinitialize the SVG element for the chart * @@ -225,7 +273,7 @@ var Chartist = { * * @memberof Chartist.Core * @param {Array} dataArray The array that contains the data to be visualized in the chart - * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart. + * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ Chartist.getHighLow = function (dataArray) { var i, @@ -250,22 +298,24 @@ var Chartist = { return highLow; }; - // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude /** * Calculate and retrieve all the bounds for the chart and return them in one array * * @memberof Chartist.Core * @param {Object} svg The svg element for the chart - * @param {Array} normalizedData The array that got updated with missing values. + * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. * @param {Object} options The Object that contains all the optional values for the chart * @param {Number} referenceValue The reference value for the chart. * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (svg, normalizedData, options, referenceValue) { + Chartist.getBounds = function (svg, highLow, options, referenceValue) { var i, newMin, newMax, - bounds = Chartist.getHighLow(normalizedData); + bounds = { + high: highLow.high, + low: highLow.low + }; // Overrides of high / low from settings bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); From cfb68aa5b761724ef7030e573f477b2c4958ec3a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 14 Dec 2014 03:33:12 +0100 Subject: [PATCH 129/593] Added stacked bar chart example --- site/data/pages/examples.yml | 9 +++++++++ site/examples/stacked-bar.js | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 site/examples/stacked-bar.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 7fd066ff..4568fd75 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -110,6 +110,15 @@ sections: Chartist will figure out if your browser supports foreignObject and it will use them to create labels that re based on regular HTML text elements. Multi-line and regular CSS styles are just two of many benefits while using foreignObjects! + - type: live-example + data: + title: Stacked bar chart + level: 4 + id: stacked-bar + classes: ct-golden-section + intro: > + You can also set your bar chart to stack the series bars on top of each other easily by using the + stackBars property in your configuration. - title: Pie chart examples level: 3 items: diff --git a/site/examples/stacked-bar.js b/site/examples/stacked-bar.js new file mode 100644 index 00000000..058b80a4 --- /dev/null +++ b/site/examples/stacked-bar.js @@ -0,0 +1,21 @@ +new Chartist.Bar('.ct-chart', { + labels: ['Q1', 'Q2', 'Q3', 'Q4'], + series: [ + [800000, 1200000, 1400000, 1300000], + [200000, 400000, 500000, 300000], + [100000, 200000, 400000, 600000] + ] +}, { + stackBars: true, + axisY: { + labelInterpolationFnc: function(value) { + return (value / 1000) + 'k'; + } + } +}).on('draw', function(data) { + if(data.type === 'bar') { + data.element.attr({ + style: 'stroke-width: 30px' + }); + } +}); From b707b4746e05fc4b989cf488fdca96a9ff466a6b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 14 Dec 2014 03:52:03 +0100 Subject: [PATCH 130/593] Added support for updating chart data after chart has been created with chart constructor, fixes #115 --- src/scripts/base.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index ad88cf73..43d7ce3b 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -16,9 +16,11 @@ /** * Updates the chart which currently does a full reconstruction of the SVG DOM * + * @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. * @memberof Chartist.Base */ - function update() { + function update(data) { + this.data = data || this.data; this.createChart(this.optionsProvider.currentOptions); return this; } From 29c35a6d1e29b1eefba6187cfa4fc79a977c6f2f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 14 Dec 2014 04:03:57 +0100 Subject: [PATCH 131/593] Added more robust functionality for chart initialization that will handle previous initializations gracefully, fixes #106 --- src/scripts/base.js | 60 ++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index 43d7ce3b..12637775 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -60,6 +60,34 @@ return this; } + function initialize() { + // Add window resize listener that re-creates the chart + window.addEventListener('resize', this.resizeListener); + + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + + // Before the first chart creation we need to register us with all plugins that are configured + // Initialize all relevant plugins with our chart object and the plugin options specified in the config + if(this.options.plugins) { + this.options.plugins.forEach(function(plugin) { + if(plugin instanceof Array) { + plugin[0](this, plugin[1]); + } else { + plugin(this); + } + }.bind(this)); + } + + // Create the first chart + this.createChart(this.optionsProvider.currentOptions); + + // As chart is initialized from the event loop now we can reset our timeout reference + // This is important if the chart gets initialized on the same element twice + this.initializeTimeoutId = undefined; + } + /** * Constructor of chart base class. * @@ -84,36 +112,22 @@ if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { - this.container.__chartist__.detach(); + if(this.container.__chartist__.initializeTimeoutId) { + // If the initializeTimeoutId is still set we can safely assume that the initialization function has not + // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach + window.clearTimeout(this.container.__chartist__.initializeTimeoutId); + } else { + // The timeout reference has already been reset which means we need to detach the old chart first + this.container.__chartist__.detach(); + } } this.container.__chartist__ = this; } - window.addEventListener('resize', this.resizeListener); - // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. - setTimeout(function() { - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); - - // Before the first chart creation we need to register us with all plugins that are configured - // Initialize all relevant plugins with our chart object and the plugin options specified in the config - if(this.options.plugins) { - this.options.plugins.forEach(function(plugin) { - if(plugin instanceof Array) { - plugin[0](this, plugin[1]); - } else { - plugin(this); - } - }.bind(this)); - } - - // Create the first chart - this.createChart(this.optionsProvider.currentOptions); - }.bind(this), 0); + this.initializeTimeoutId = setTimeout(initialize.bind(this), 0); } // Creating the chart base class From 68f56e4ca60fa829b6c0acae12b2e2a2fb5fa2dd Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 14 Dec 2014 04:13:15 +0100 Subject: [PATCH 132/593] Update to 0.5.0 --- CHANGELOG.md | 7 + bower.json | 2 +- dist/chartist.js | 469 ++++++++++++++++++++------------------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- src/scripts/core.js | 2 +- 8 files changed, 259 insertions(+), 231 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69a0545d..557cc679 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v0.5.0 - 14 Dec 2014 +-------------------- +- Added new option for line and bar chart to use full width of the chart area by skipping the last grid line +- Added new option for bar chart to create stacked bar charts +- All chart update functions now accepts an optional data parameter that allows to update an existing chart with new data +- Fix for an error when charts get re-constructed on the same element and in the same call stack + v0.4.4 - 11 Dec 2014 -------------------- - Fixed NS_ERROR_FAILURE error in Firefox and added graceful handling of unsupported SMIL animations (i.e. in foreignObjects) diff --git a/bower.json b/bower.json index 875cb461..97b11ce8 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.4.4", + "version": "0.5.0", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index ff968147..8d7b2957 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { - /* Chartist.js 0.4.4 + /* Chartist.js 0.5.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.4.4' + version: '0.5.0' }; (function (window, document, Chartist) { @@ -121,6 +121,54 @@ return query instanceof Node ? query : document.querySelector(query); }; + /** + * Functional style helper to produce array with given length initialized with undefined values + * + * @memberof Chartist.Core + * @param length + * @returns {Array} + */ + Chartist.times = function(length) { + return Array.apply(null, new Array(length)); + }; + + /** + * Sum helper to be used in reduce functions + * + * @memberof Chartist.Core + * @param previous + * @param current + * @returns {*} + */ + Chartist.sum = function(previous, current) { + return previous + current; + }; + + /** + * 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). + * + * @memberof Chartist.Core + * @param arr + * @param cb + * @returns {Array} + */ + Chartist.serialMap = function(arr, cb) { + var result = [], + length = Math.max.apply(null, arr.map(function(e) { + return e.length; + })); + + Chartist.times(length).forEach(function(e, index) { + var args = arr.map(function(e) { + return e[index]; + }); + + result[index] = cb.apply(null, args); + }); + + return result; + }; + /** * Create or reinitialize the SVG element for the chart * @@ -246,7 +294,7 @@ * * @memberof Chartist.Core * @param {Array} dataArray The array that contains the data to be visualized in the chart - * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart. + * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ Chartist.getHighLow = function (dataArray) { var i, @@ -271,22 +319,24 @@ return highLow; }; - // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude /** * Calculate and retrieve all the bounds for the chart and return them in one array * * @memberof Chartist.Core * @param {Object} svg The svg element for the chart - * @param {Array} normalizedData The array that got updated with missing values. + * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. * @param {Object} options The Object that contains all the optional values for the chart * @param {Number} referenceValue The reference value for the chart. * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (svg, normalizedData, options, referenceValue) { + Chartist.getBounds = function (svg, highLow, options, referenceValue) { var i, newMin, newMax, - bounds = Chartist.getHighLow(normalizedData); + bounds = { + high: highLow.high, + low: highLow.low + }; // Overrides of high / low from settings bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); @@ -442,7 +492,7 @@ // Create X-Axis data.labels.forEach(function (value, index) { var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - width = chartRect.width() / data.labels.length, + width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)), height = options.axisX.offset, pos = chartRect.x1 + width * index; @@ -598,11 +648,12 @@ * @param {Object} bounds All the values to set the bounds of the chart * @param {Array} data The array that contains the data to be visualized in the chart * @param {Number} index The index of the current project point + * @param {Object} options The chart options that are used to influence the calculations * @return {Object} The coordinates object of the current project point containing an x and y number property */ - Chartist.projectPoint = function (chartRect, bounds, data, index) { + Chartist.projectPoint = function (chartRect, bounds, data, index, options) { return { - x: chartRect.x1 + chartRect.width() / data.length * index, + x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index, y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) }; }; @@ -1026,9 +1077,11 @@ /** * Updates the chart which currently does a full reconstruction of the SVG DOM * + * @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. * @memberof Chartist.Base */ - function update() { + function update(data) { + this.data = data || this.data; this.createChart(this.optionsProvider.currentOptions); return this; } @@ -1068,6 +1121,34 @@ return this; } + function initialize() { + // Add window resize listener that re-creates the chart + window.addEventListener('resize', this.resizeListener); + + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + + // Before the first chart creation we need to register us with all plugins that are configured + // Initialize all relevant plugins with our chart object and the plugin options specified in the config + if(this.options.plugins) { + this.options.plugins.forEach(function(plugin) { + if(plugin instanceof Array) { + plugin[0](this, plugin[1]); + } else { + plugin(this); + } + }.bind(this)); + } + + // Create the first chart + this.createChart(this.optionsProvider.currentOptions); + + // As chart is initialized from the event loop now we can reset our timeout reference + // This is important if the chart gets initialized on the same element twice + this.initializeTimeoutId = undefined; + } + /** * Constructor of chart base class. * @@ -1092,36 +1173,22 @@ if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { - this.container.__chartist__.detach(); + if(this.container.__chartist__.initializeTimeoutId) { + // If the initializeTimeoutId is still set we can safely assume that the initialization function has not + // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach + window.clearTimeout(this.container.__chartist__.initializeTimeoutId); + } else { + // The timeout reference has already been reset which means we need to detach the old chart first + this.container.__chartist__.detach(); + } } this.container.__chartist__ = this; } - window.addEventListener('resize', this.resizeListener); - // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. - setTimeout(function() { - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); - - // Before the first chart creation we need to register us with all plugins that are configured - // Initialize all relevant plugins with our chart object and the plugin options specified in the config - if(this.options.plugins) { - this.options.plugins.forEach(function(plugin) { - if(plugin instanceof Array) { - plugin[0](this, plugin[1]); - } else { - plugin(this); - } - }.bind(this)); - } - - // Create the first chart - this.createChart(this.optionsProvider.currentOptions); - }.bind(this), 0); + this.initializeTimeoutId = setTimeout(initialize.bind(this), 0); } // Creating the chart base class @@ -1747,38 +1814,69 @@ (function(window, document, Chartist){ 'use strict'; + /** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Line + */ var defaultOptions = { + // Options for X-Axis axisX: { + // The offset of the labels to the chart area offset: 30, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop }, + // Options for Y-Axis axisY: { + // The offset of the labels to the chart area offset: 40, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20 }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, + // If the line should be drawn or not showLine: true, + // If dots should be drawn or not showPoint: true, + // If the line chart should draw an area showArea: false, + // The base for the area chart that will be used to close the area shape (is normally 0) areaBase: 0, + // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) lineSmooth: true, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, + // Padding of the chart drawing area to the container element and labels chartPadding: 5, + // 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. + fullWidth: false, + // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-line', label: 'ct-label', @@ -1794,6 +1892,10 @@ } }; + /** + * Creates a new chart + * + */ function createChart(options) { var seriesGroups = [], bounds, @@ -1803,7 +1905,7 @@ this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options); + bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options); var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing @@ -1836,7 +1938,7 @@ point; for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j); + p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options); pathCoordinates.push(p.x, p.y); //If we should show points we need to create them now to avoid secondary loop @@ -1890,7 +1992,7 @@ var areaPathElements = pathElements.slice(); // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0); + var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options); // And splice our new area path array to add the missing path elements to close the area shape areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; @@ -1949,79 +2051,6 @@ * @return {Object} An object which exposes the API for the created chart * * @example - * // These are the default options of the line chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the labels to the chart area - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the labels to the chart area - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // If the line should be drawn or not - * showLine: true, - * // If dots should be drawn or not - * showPoint: true, - * // If the line chart should draw an area - * showArea: false, - * // The base for the area chart that will be used to close the area shape (is normally 0) - * areaBase: 0, - * // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) - * lineSmooth: true, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * 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', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example * // Create a simple line chart * var data = { * // A labels array that can contain any sort of values @@ -2102,34 +2131,65 @@ (function(window, document, Chartist){ 'use strict'; + /** + * Default options in bar charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Bar + */ var defaultOptions = { + // Options for X-Axis axisX: { + // The offset of the chart drawing area to the border of the container offset: 30, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop }, + // Options for Y-Axis axisY: { + // The offset of the chart drawing area to the border of the container offset: 40, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, + // If labels should be shown or not showLabel: true, + // If the axis grid should be drawn or not showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20 }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Padding of the chart drawing area to the container element and labels chartPadding: 5, + // Specify the distance in pixel of bars in a group seriesBarDistance: 15, + // 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. For bar charts this might be used in conjunction with the centerBars property set to false. + fullWidth: false, + // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property. + centerBars: true, + // If set to true this property will cause the series bars to be stacked and 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. + stackBars: false, + // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', label: 'ct-label', @@ -2143,23 +2203,41 @@ } }; + /** + * Creates a new chart + * + */ function createChart(options) { var seriesGroups = [], bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length), + highLow; // Create new svg element this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + if(options.stackBars) { + // If stacked bars we need to calculate the high low from stacked values from each series + var serialSums = Chartist.serialMap(normalizedData, function serialSums() { + return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); + }); + + highLow = Chartist.getHighLow([serialSums]); + } else { + highLow = Chartist.getHighLow(normalizedData); + } + // initialize bounds - bounds = Chartist.getBounds(this.svg, normalizedData, options, 0); + bounds = Chartist.getBounds(this.svg, highLow, options, 0); var chartRect = Chartist.createChartRect(this.svg, options); // Start drawing var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), grid = this.svg.elem('g').addClass(options.classNames.gridGroup), - // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0); + // Projected 0 point + zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options), + // Used to track the screen coordinates of stacked bars + stackedBarValues = []; Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); @@ -2169,8 +2247,8 @@ for (var i = 0; i < this.data.series.length; i++) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. var biPol = i - (this.data.series.length - 1) / 2, - // Half of the period with between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / normalizedData[i].length / 2; + // Half of the period width between vertical grid lines used to position bars + periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2; seriesGroups[i] = this.svg.elem('g'); @@ -2188,18 +2266,30 @@ ].join(' ')); for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j), - bar; + var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options), + bar, + previousStack, + y1, + y2; + + // Offset to center bar between grid lines + p.x += (options.centerBars ? periodHalfWidth : 0); + // Using bi-polar offset for multiple series if no stacked bars are used + p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance; - // Offset to center bar between grid lines and using bi-polar offset for multiple series - // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors - p.x += periodHalfWidth + (biPol * options.seriesBarDistance); + // Enter value in stacked bar values used to remember previous screen value for stacking up bars + previousStack = stackedBarValues[j] || zeroPoint.y; + stackedBarValues[j] = previousStack - (zeroPoint.y - p.y); + + // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line + y1 = options.stackBars ? previousStack : zeroPoint.y; + y2 = options.stackBars ? stackedBarValues[j] : p.y; bar = seriesGroups[i].elem('line', { x1: p.x, - y1: zeroPoint.y, + y1: y1, x2: p.x, - y2: p.y + y2: y2 }, options.classNames.bar).attr({ 'value': normalizedData[i][j] }, Chartist.xmlNs.uri); @@ -2211,9 +2301,9 @@ group: seriesGroups[i], element: bar, x1: p.x, - y1: zeroPoint.y, + y1: y1, x2: p.x, - y2: p.y + y2: y2 }); } } @@ -2237,69 +2327,6 @@ * @return {Object} An object which exposes the API for the created chart * * @example - * // These are the default options of the bar chart - * var options = { - * // Options for X-Axis - * axisX: { - * // The offset of the chart drawing area to the border of the container - * offset: 30, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;} - * }, - * // Options for Y-Axis - * axisY: { - * // The offset of the chart drawing area to the border of the container - * offset: 40, - * // Allows you to correct label positioning on this axis by positive or negative x and y offset. - * labelOffset: { - * x: 0, - * y: 0 - * }, - * // If labels should be shown or not - * showLabel: true, - * // If the axis grid should be drawn or not - * showGrid: true, - * // Interpolation function that allows you to intercept the value from the axis label - * labelInterpolationFnc: function(value){return value;}, - * // This value specifies the minimum height in pixel of the scale steps - * scaleMinSpace: 30 - * }, - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - * low: undefined, - * // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - * high: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Specify the distance in pixel of bars in a group - * seriesBarDistance: 15, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-bar', - * label: 'ct-label', - * labelGroup: 'ct-labels', - * series: 'ct-series', - * bar: 'ct-bar', - * grid: 'ct-grid', - * gridGroup: 'ct-grids', - * vertical: 'ct-vertical', - * horizontal: 'ct-horizontal' - * } - * }; - * - * @example * // Create a simple bar chart * var data = { * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], @@ -2350,10 +2377,19 @@ (function(window, document, Chartist) { 'use strict'; + /** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Pie + */ var defaultOptions = { + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, + // Padding of the chart drawing area to the container element and labels chartPadding: 5, + // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-pie', series: 'ct-series', @@ -2361,17 +2397,32 @@ donut: 'ct-donut', label: 'ct-label' }, + // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. startAngle: 0, + // 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. total: undefined, + // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. donut: false, + // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. donutWidth: 60, + // If a label should be shown or not showLabel: true, + // 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. labelOffset: 0, + // An interpolation function for the label value labelInterpolationFnc: Chartist.noop, - labelOverflow: false, + // 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. labelDirection: 'neutral' }; + /** + * Determines SVG anchor position based on direction and center parameter + * + * @param center + * @param label + * @param direction + * @returns {string} + */ function determineAnchorPosition(center, label, direction) { var toTheRight = label.x > center.x; @@ -2386,6 +2437,11 @@ } } + /** + * Creates the pie chart + * + * @param options + */ function createChart(options) { var seriesGroups = [], chartRect, @@ -2547,41 +2603,6 @@ * @return {Object} An object with a version and an update method to manually redraw the chart * * @example - * // Default options of the pie chart - * var defaultOptions = { - * // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - * width: undefined, - * // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - * height: undefined, - * // Padding of the chart drawing area to the container element and labels - * chartPadding: 5, - * // Override the class names that get used to generate the SVG structure of the chart - * classNames: { - * chart: 'ct-chart-pie', - * series: 'ct-series', - * slice: 'ct-slice', - * donut: 'ct-donut', - label: 'ct-label' - * }, - * // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. - * startAngle: 0, - * // 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. - * total: undefined, - * // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. - * donut: false, - * // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. - * donutWidth: 60, - * // If a label should be shown or not - * showLabel: true, - * // 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. - * labelOffset: 0, - * // An interpolation function for the label value - * labelInterpolationFnc: function(value, index) {return value;}, - * // 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. - * labelDirection: 'neutral' - * }; - * - * @example * // Simple pie chart example with four series * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 75a118cc..32aff3f4 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.4.4 +/* Chartist.js 0.5.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 4d909fb0..5506fa14 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.4.4 +/* Chartist.js 0.5.0 * Copyright © 2014 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.4.4"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/d.labels.length,n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d){return{x:a.x1+a.width()/c.length*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelOverflow:!1,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.5.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index f9e5676c..c60ad109 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","length","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","max","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","normalizedData","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","index","interpolatedValue","labelInterpolationFnc","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":19091,"pos":19086,"col":16,"line":502,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","arr","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","apply","super","mix","mixProtoArr","Error","superPrototypes","concat","map","Function","mixedSuperProto","args","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","Base","isSupported","supportsAnimations","bind","__chartist__","addEventListener","setTimeout","plugins","plugin","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","zeroPoint","biPol","periodHalfWidth","bar","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","reduce","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie","labelOverflow"],"mappings":";;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,UAAW,WACT,MAAQF,GAAKI,oBAAsBH,MAET,gBAAZI,SAIhBC,OAAOD,QAAUJ,IAEjBD,EAAe,SAAIC,KAErBM,KAAM,WAYN,GAAIC,IACFC,QAAS,QA+jFX,OA5jFC,UAAUC,EAAQC,EAAUH,GAC3B,YASAA,GAASI,KAAO,SAAUC,GACxB,MAAOA,IAUTL,EAASM,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAWtCL,EAASS,OAAS,SAAUC,GAC1BA,EAASA,KAET,IAAIC,GAAUC,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,EAWpD,OAVAL,GAAQM,QAAQ,SAASC,GACvB,IAAK,GAAIC,KAAQD,GAIbR,EAAOS,GAHmB,gBAAjBD,GAAOC,IAAwBD,EAAOC,YAAiBP,OAGjDM,EAAOC,GAFPnB,EAASS,OAAOC,EAAOS,GAAOD,EAAOC,MAOnDT,GAUTV,EAASoB,UAAY,SAASC,GAK5B,MAJoB,gBAAVA,KACRA,EAAQA,EAAMC,QAAQ,eAAgB,MAGhCD,GAWVrB,EAASuB,WAAa,SAASF,EAAOG,GAKpC,MAJoB,gBAAVH,KACRA,GAAgBG,GAGXH,GAUTrB,EAASyB,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQvB,EAASsB,cAAcC,IAahE1B,EAAS4B,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIC,EAqBJ,OAnBAH,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAEnBE,EAAMJ,EAAUJ,cAAc,OAC3BQ,GACDJ,EAAUK,YAAYD,GAIxBA,EAAM,GAAIjC,GAASmC,IAAI,OAAOC,MAC5BN,MAAOA,EACPC,OAAQA,IACPM,SAASL,GAAWI,MACrBE,MAAO,UAAYR,EAAQ,aAAeC,EAAS,MAIrDF,EAAUU,YAAYN,EAAIO,OAEnBP,GAUTjC,EAASyC,aAAe,SAAUC,GAGhC,IAAK,GAFDC,MAEKC,EAAI,EAAGA,EAAIF,EAAKG,OAAOC,OAAQF,IAAK,CAG3CD,EAAMC,GAAgC,gBAApBF,GAAKG,OAAOD,IAA4CG,SAAxBL,EAAKG,OAAOD,GAAGF,KAC/DA,EAAKG,OAAOD,GAAGF,KAAOA,EAAKG,OAAOD,EAGpC,KAAK,GAAII,GAAI,EAAGA,EAAIL,EAAMC,GAAGE,OAAQE,IACnCL,EAAMC,GAAGI,IAAML,EAAMC,GAAGI,GAI5B,MAAOL,IAWT3C,EAASiD,mBAAqB,SAAUC,EAAWJ,GACjD,IAAK,GAAIF,GAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IACpC,GAAIM,EAAUN,GAAGE,SAAWA,EAI5B,IAAK,GAAIE,GAAIE,EAAUN,GAAGE,OAAYA,EAAJE,EAAYA,IAC5CE,EAAUN,GAAGI,GAAK,CAItB,OAAOE,IAUTlD,EAASmD,iBAAmB,SAAU9B,GACpC,MAAO+B,MAAKC,MAAMD,KAAKE,IAAIF,KAAKG,IAAIlC,IAAU+B,KAAKI,OAarDxD,EAASyD,cAAgB,SAAUxB,EAAKa,EAAQY,EAAQC,GACtD,GAAIC,GAAkB5D,EAAS6D,mBAAmB5B,EAAK0B,EACvD,OAAQb,GAASY,EAAOI,MAAQF,GAWlC5D,EAAS6D,mBAAqB,SAAU5B,EAAK0B,GAC3C,MAAOP,MAAKW,KAAK/D,EAASoB,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAoC,EAAvB4B,EAAQK,aAAoBL,EAAQM,MAAMC,OAAQ,IAU5HlE,EAASmE,WAAa,SAAUjB,GAC9B,GAAIN,GACFI,EACAoB,GACEC,MAAOC,OAAOC,UACdC,IAAKF,OAAOC,UAGhB,KAAK3B,EAAI,EAAGA,EAAIM,EAAUJ,OAAQF,IAChC,IAAKI,EAAI,EAAGA,EAAIE,EAAUN,GAAGE,OAAQE,IAC/BE,EAAUN,GAAGI,GAAKoB,EAAQC,OAC5BD,EAAQC,KAAOnB,EAAUN,GAAGI,IAG1BE,EAAUN,GAAGI,GAAKoB,EAAQI,MAC5BJ,EAAQI,IAAMtB,EAAUN,GAAGI,GAKjC,OAAOoB,IAcTpE,EAASyE,UAAY,SAAUxC,EAAKyC,EAAgBf,EAASgB,GAC3D,GAAI/B,GACFgC,EACAC,EACAnB,EAAS1D,EAASmE,WAAWO,EAG/BhB,GAAOW,MAAQV,EAAQU,OAA0B,IAAjBV,EAAQU,KAAa,EAAIX,EAAOW,MAChEX,EAAOc,KAAOb,EAAQa,MAAwB,IAAhBb,EAAQa,IAAY,EAAId,EAAOc,KAI1Dd,EAAOW,OAASX,EAAOc,MAEN,IAAfd,EAAOc,IACRd,EAAOW,KAAO,EACNX,EAAOc,IAAM,EAErBd,EAAOW,KAAO,EAGdX,EAAOc,IAAM,IAObG,GAAqC,IAAnBA,KACpBjB,EAAOW,KAAOjB,KAAKW,IAAIY,EAAgBjB,EAAOW,MAC9CX,EAAOc,IAAMpB,KAAK0B,IAAIH,EAAgBjB,EAAOc,MAG/Cd,EAAOqB,WAAarB,EAAOW,KAAOX,EAAOc,IACzCd,EAAOsB,IAAMhF,EAASmD,iBAAiBO,EAAOqB,YAC9CrB,EAAOoB,IAAM1B,KAAKC,MAAMK,EAAOc,IAAMpB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOK,IAAMX,KAAK8B,KAAKxB,EAAOW,KAAOjB,KAAK6B,IAAI,GAAIvB,EAAOsB,MAAQ5B,KAAK6B,IAAI,GAAIvB,EAAOsB,KACrFtB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IACnCpB,EAAOyB,KAAO/B,KAAK6B,IAAI,GAAIvB,EAAOsB,KAClCtB,EAAO0B,cAAgBhC,KAAKiC,MAAM3B,EAAOI,MAAQJ,EAAOyB,KAOxD,KAHA,GAAIrC,GAAS9C,EAASyD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,GAC5D2B,EAAUxC,EAASa,EAAQ4B,MAAMC,gBAGjC,GAAIF,GAAWtF,EAASyD,cAAcxB,EAAKyB,EAAOyB,KAAMzB,EAAQC,IAAYA,EAAQ4B,MAAMC,cACxF9B,EAAOyB,MAAQ,MACV,CAAA,GAAKG,KAAWtF,EAASyD,cAAcxB,EAAKyB,EAAOyB,KAAO,EAAGzB,EAAQC,IAAYA,EAAQ4B,MAAMC,eAGpG,KAFA9B,GAAOyB,MAAQ,EASnB,IAFAP,EAASlB,EAAOoB,IAChBD,EAASnB,EAAOK,IACXnB,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAC5CvC,EAAIc,EAAOyB,KAAOzB,EAAOc,MAC3BI,GAAUlB,EAAOyB,MAGfvC,EAAIc,EAAOyB,MAAQzB,EAAOW,OAC5BQ,GAAUnB,EAAOyB,KAQrB,KALAzB,EAAOoB,IAAMF,EACblB,EAAOK,IAAMc,EACbnB,EAAOI,MAAQJ,EAAOK,IAAML,EAAOoB,IAEnCpB,EAAO+B,UACF7C,EAAIc,EAAOoB,IAAKlC,GAAKc,EAAOK,IAAKnB,GAAKc,EAAOyB,KAChDzB,EAAO+B,OAAOC,KAAK9C,EAGrB,OAAOc,IAaT1D,EAAS2F,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAM3C,KAAK6C,GAAK,GAEvD,QACEC,EAAGN,EAAWE,EAAS1C,KAAK+C,IAAIH,GAChCI,EAAGP,EAAWC,EAAS1C,KAAKiD,IAAIL,KAYpChG,EAASsG,gBAAkB,SAAUrE,EAAK0B,GACxC,GAAI4C,GAAU5C,EAAQ4B,MAAQ5B,EAAQ4B,MAAMrB,OAAS,EACnDsC,EAAU7C,EAAQM,MAAQN,EAAQM,MAAMC,OAAS,CAEnD,QACEuC,GAAI9C,EAAQK,aAAeuC,EAC3BG,GAAItD,KAAKW,KAAK/D,EAASoB,UAAUuC,EAAQ5B,SAAWE,EAAIF,UAAY4B,EAAQK,aAAewC,EAAS7C,EAAQK,cAC5G2C,GAAIvD,KAAKW,KAAK/D,EAASoB,UAAUuC,EAAQ7B,QAAUG,EAAIH,SAAW6B,EAAQK,aAAcL,EAAQK,aAAeuC,GAC/GK,GAAIjD,EAAQK,aACZlC,MAAO,WACL,MAAO/B,MAAK4G,GAAK5G,KAAK0G,IAExB1E,OAAQ,WACN,MAAOhC,MAAK2G,GAAK3G,KAAK6G,MAe5B5G,EAAS6G,YAAc,SAASC,EAAQC,EAAMC,EAAYhF,EAAWiF,GACnE,GAAGA,EAAuB,CACxB,GAAIC,GAAU,gBAAkBlF,EAAY,KAAO+E,EAAO,SAC1D,OAAOD,GAAOK,cAAcD,EAASF,GAErC,MAAOF,GAAOM,KAAK,OAAQJ,EAAYhF,GAAW+E,KAAKA,IAgB3D/G,EAASqH,YAAc,SAAUC,EAAW5E,EAAM6E,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAErFvE,EAAK8E,OAAOvG,QAAQ,SAAUI,EAAOqG,GACnC,GAAIC,GAAoBhE,EAAQM,MAAM2D,sBAAsBvG,EAAOqG,GACjE5F,EAAQwF,EAAUxF,QAAUY,EAAK8E,OAAO1E,OACxCf,EAAS4B,EAAQM,MAAMC,OACvB2D,EAAMP,EAAUb,GAAK3E,EAAQ4F,CAG/B,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIhE,EAAQM,MAAM6D,SAAU,CAC1B,GAAIC,GAAcR,EAAKH,KAAK,QAC1BX,GAAIoB,EACJnB,GAAIY,EAAUZ,GACdC,GAAIkB,EACJjB,GAAIU,EAAUV,KACZjD,EAAQqE,WAAWT,KAAM5D,EAAQqE,WAAWC,YAAYC,KAAK,KAGjET,GAAaU,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASR,EACTtB,GAAIoB,EACJnB,GAAIY,EAAUZ,GACdC,GAAIkB,EACJjB,GAAIU,EAAUV,KAIlB,GAAIjD,EAAQM,MAAMuE,UAAW,CAC3B,GAAIC,IACFvC,EAAG2B,EAAMlE,EAAQM,MAAMyE,YAAYxC,EACnCE,EAAGkB,EAAUZ,GAAK/C,EAAQM,MAAMyE,YAAYtC,GAAKa,EAAwB,EAAI,KAG3E0B,EAAe3I,EAAS6G,YAAYW,EAAQ,GAAKG,GACnDzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQqE,WAAWY,MAAOjF,EAAQqE,WAAWC,YAAYC,KAAK,KAAMjB,EAExEQ,GAAaU,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOd,EACPe,QAASI,EACT5B,KAAM,GAAKY,EACXzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EAER8G,GAAIC,SAEF,MADA5I,GAAO6I,QAAQC,KAAK,mEACbjJ,KAAK+B,cAmBtB9B,EAASiJ,YAAc,SAAU3B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS8D,EAAcR,GAEvFvD,EAAO+B,OAAOxE,QAAQ,SAAUI,EAAOqG,GACrC,GAAIC,GAAoBhE,EAAQ4B,MAAMqC,sBAAsBvG,EAAOqG,GACjE5F,EAAQ6B,EAAQ4B,MAAMrB,OACtBnC,EAASuF,EAAUvF,SAAW2B,EAAO+B,OAAO3C,OAC5C+E,EAAMP,EAAUZ,GAAK3E,EAAS2F,CAGhC,IAAKC,GAA2C,IAAtBA,EAA1B,CAIA,GAAIhE,EAAQ4B,MAAMuC,SAAU,CAC1B,GAAIC,GAAcR,EAAKH,KAAK,QAC1BX,GAAIa,EAAUb,GACdC,GAAImB,EACJlB,GAAIW,EAAUX,GACdC,GAAIiB,IACFlE,EAAQqE,WAAWT,KAAM5D,EAAQqE,WAAWkB,UAAUhB,KAAK,KAG/DT,GAAaU,KAAK,QAChBC,KAAM,OACNC,KAAM,IACNX,MAAOA,EACPY,MAAOf,EACPgB,QAASR,EACTtB,GAAIa,EAAUb,GACdC,GAAImB,EACJlB,GAAIW,EAAUX,GACdC,GAAIiB,IAIR,GAAIlE,EAAQ4B,MAAMiD,UAAW,CAC3B,GAAIC,IACFvC,EAAGvC,EAAQK,aAAeL,EAAQ4B,MAAMmD,YAAYxC,GAAKe,EAAwB,IAAM,GACvFb,EAAGyB,EAAMlE,EAAQ4B,MAAMmD,YAAYtC,GAAKa,EAAwB,IAAM,IAGpE0B,EAAe3I,EAAS6G,YAAYW,EAAQ,GAAKG,GACnDzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EACRO,MAAO,uBACLqB,EAAQqE,WAAWY,MAAOjF,EAAQqE,WAAWkB,UAAUhB,KAAK,KAAMjB,EAEtEQ,GAAaU,KAAK,QAChBC,KAAM,QACNC,KAAM,IACNX,MAAOA,EACPY,MAAOd,EACPe,QAASI,EACT5B,KAAM,GAAKY,EACXzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,EACjBtE,MAAOA,EACPC,OAAQA,EAER8G,GAAIC,SAEF,MADA5I,GAAO6I,QAAQC,KAAK,mEACbjJ,KAAKgC,eAiBtB/B,EAASmJ,aAAe,SAAU7B,EAAW5D,EAAQhB,EAAMgF,GACzD,OACExB,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAUY,EAAKI,OAAS4E,EACpDtB,EAAGkB,EAAUZ,GAAKY,EAAUvF,UAAYW,EAAKgF,GAAShE,EAAOoB,MAAQpB,EAAOI,MAAQJ,EAAOyB,QAc/FnF,EAASoJ,gBAAkB,SAAUzF,EAAS0F,EAAmB5B,GAM/D,QAAS6B,KACP,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiBxJ,EAASS,UAAWgJ,GAEjCJ,EACF,IAAKzG,EAAI,EAAGA,EAAIyG,EAAkBvG,OAAQF,IAAK,CAC7C,GAAI8G,GAAMxJ,EAAOyJ,WAAWN,EAAkBzG,GAAG,GAC7C8G,GAAIE,UACNJ,EAAiBxJ,EAASS,OAAO+I,EAAgBH,EAAkBzG,GAAG,KAKzE6E,GACDA,EAAaU,KAAK,kBAChBoB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoB7I,QAAQ,SAASyI,GACnCA,EAAIK,eAAeT,KA5BvB,GACEE,GAEA5G,EAHE6G,EAAczJ,EAASS,UAAWkD,GAEpCmG,IA8BF,KAAK5J,EAAOyJ,WACV,KAAM,iEACD,IAAIN,EAET,IAAKzG,EAAI,EAAGA,EAAIyG,EAAkBvG,OAAQF,IAAK,CAC7C,GAAI8G,GAAMxJ,EAAOyJ,WAAWN,EAAkBzG,GAAG,GACjD8G,GAAIM,YAAYV,GAChBQ,EAAoBpE,KAAKgE,GAM7B,MAFAJ,MAGET,GAAIW,kBACF,MAAOxJ,GAASS,UAAW+I,IAE7BK,0BAA2BA,IAK/B7J,EAASiK,kBAAoB,SAAUC,EAAKC,GAE1C,IAAK,GADDC,MACKxH,EAAI,EAAGyH,EAAOH,EAAIpH,OAAQuH,EAAO,GAAKF,EAAIvH,EAAGA,GAAK,EAAG,CAC5D,GAAI0H,KACDpE,GAAIgE,EAAItH,EAAI,GAAIwD,GAAI8D,EAAItH,EAAI,KAC5BsD,GAAIgE,EAAItH,GAAIwD,GAAI8D,EAAItH,EAAI,KACxBsD,GAAIgE,EAAItH,EAAI,GAAIwD,GAAI8D,EAAItH,EAAI,KAC5BsD,GAAIgE,EAAItH,EAAI,GAAIwD,GAAI8D,EAAItH,EAAI,IAE3BuH,GACGvH,EAEMyH,EAAO,IAAMzH,EACtB0H,EAAE,IAAMpE,GAAIgE,EAAI,GAAI9D,GAAI8D,EAAI,IACnBG,EAAO,IAAMzH,IACtB0H,EAAE,IAAMpE,GAAIgE,EAAI,GAAI9D,GAAI8D,EAAI,IAC5BI,EAAE,IAAMpE,GAAIgE,EAAI,GAAI9D,GAAI8D,EAAI,KAL5BI,EAAE,IAAMpE,GAAIgE,EAAIG,EAAO,GAAIjE,GAAI8D,EAAIG,EAAO,IAQxCA,EAAO,IAAMzH,EACf0H,EAAE,GAAKA,EAAE,GACC1H,IACV0H,EAAE,IAAMpE,GAAIgE,EAAItH,GAAIwD,GAAI8D,EAAItH,EAAI,KAGpCwH,EAAE1E,QAEI4E,EAAE,GAAGpE,EAAI,EAAIoE,EAAE,GAAGpE,EAAIoE,EAAE,GAAGpE,GAAK,IAChCoE,EAAE,GAAGlE,EAAI,EAAIkE,EAAE,GAAGlE,EAAIkE,EAAE,GAAGlE,GAAK,GACjCkE,EAAE,GAAGpE,EAAI,EAAIoE,EAAE,GAAGpE,EAAIoE,EAAE,GAAGpE,GAAK,GAChCoE,EAAE,GAAGlE,EAAI,EAAIkE,EAAE,GAAGlE,EAAIkE,EAAE,GAAGlE,GAAK,EACjCkE,EAAE,GAAGpE,EACLoE,EAAE,GAAGlE,IAKX,MAAOgE,KAGTlK,OAAQC,SAAUH,GAOnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAASuK,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAO/E,KAAKgF,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAO3H,cACV6H,GAASF,UAIXE,GAASF,IAYtB,QAAStC,GAAKsC,EAAO/H,GAEhBiI,EAASF,IACVE,EAASF,GAAOxJ,QAAQ,SAASyJ,GAC/BA,EAAQhI,KAKTiI,EAAS,MACVA,EAAS,KAAK1J,QAAQ,SAAS8J,GAC7BA,EAAYN,EAAO/H,KAvDzB,GAAIiI,KA4DJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpBzC,KAAMA,KAIVjI,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAASgL,GAAYC,GACnB,GAAIC,KACJ,IAAID,EAAKnI,OACP,IAAK,GAAIF,GAAI,EAAGA,EAAIqI,EAAKnI,OAAQF,IAC/BsI,EAAIxF,KAAKuF,EAAKrI,GAGlB,OAAOsI,GA4CT,QAASzK,GAAO0K,EAAYC,GAC1B,GAAIC,GAAaD,GAAsBrL,KAAKc,WAAab,EAASsL,MAC9DC,EAAQC,OAAOC,OAAOJ,EAE1BrL,GAASsL,MAAMI,iBAAiBH,EAAOJ,EAEvC,IAAIQ,GAAS,WACX,GACEC,GADEC,EAAKN,EAAMO,aAAe,YAU9B,OALAF,GAAW7L,OAASC,EAAWwL,OAAOC,OAAOF,GAASxL,KACtD8L,EAAGE,MAAMH,EAAUhL,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,IAIlD4K,EAOT,OAJAD,GAAO9K,UAAY0K,EACnBI,EAAOK,MAAQX,EACfM,EAAOlL,OAASV,KAAKU,OAEdkL,EA0FT,QAASM,GAAIC,EAAaf,GACxB,GAAGpL,OAASC,EAASsL,MACnB,KAAM,IAAIa,OAAM,iFAIlB,IAAIC,QACDC,OAAOH,GACPI,IAAI,SAAUzL,GACb,MAAOA,aAAqB0L,UAAW1L,EAAUA,UAAYA,IAG7D2L,EAAkBxM,EAASsL,MAAMI,iBAAiBK,MAAMhJ,OAAWqJ,EAGvE,cADOI,GAAgBV,YAChB/L,KAAKU,OAAO0K,EAAYqB,GAIjC,QAASd,KACP,GAAIe,GAAOzB,EAAYhK,WACnBN,EAAS+L,EAAK,EAYlB,OAVAA,GAAK5B,OAAO,EAAG4B,EAAK3J,OAAS,GAAG7B,QAAQ,SAAUC,GAChDsK,OAAOkB,oBAAoBxL,GAAQD,QAAQ,SAAU0L,SAE5CjM,GAAOiM,GAEdnB,OAAOoB,eAAelM,EAAQiM,EAC5BnB,OAAOqB,yBAAyB3L,EAAQyL,QAIvCjM,EAGTV,EAASsL,OACP7K,OAAQA,EACRwL,IAAKA,EACLP,iBAAkBA,IAGpBxL,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAaA,SAAS8M,KAEP,MADA/M,MAAKgN,YAAYhN,KAAKqJ,gBAAgBI,gBAC/BzJ,KAQT,QAASiN,KAGP,MAFA9M,GAAO+M,oBAAoB,SAAUlN,KAAKmN,gBAC1CnN,KAAKqJ,gBAAgBS,4BACd9J,KAUT,QAASoN,GAAG1C,EAAOC,GAEjB,MADA3K,MAAK0H,aAAa+C,gBAAgBC,EAAOC,GAClC3K,KAUT,QAASqN,GAAI3C,EAAOC,GAElB,MADA3K,MAAK0H,aAAamD,mBAAmBH,EAAOC,GACrC3K,KAYT,QAASsN,GAAK3L,EAAOgB,EAAMiB,EAAS0F,GAClCtJ,KAAK8B,UAAY7B,EAASyB,cAAcC,GACxC3B,KAAK2C,KAAOA,EACZ3C,KAAK4D,QAAUA,EACf5D,KAAKsJ,kBAAoBA,EACzBtJ,KAAK0H,aAAezH,EAASuK,eAC7BxK,KAAKkH,sBAAwBjH,EAASmC,IAAImL,YAAY,iBACtDvN,KAAKwN,mBAAqBvN,EAASmC,IAAImL,YAAY,4BACnDvN,KAAKmN,eAAiB,WACpBnN,KAAK+M,UACLU,KAAKzN,MAEJA,KAAK8B,YAEH9B,KAAK8B,UAAU4L,cAChB1N,KAAK8B,UAAU4L,aAAaT,SAG9BjN,KAAK8B,UAAU4L,aAAe1N,MAGhCG,EAAOwN,iBAAiB,SAAU3N,KAAKmN,gBAIvCS,WAAW,WAGT5N,KAAKqJ,gBAAkBpJ,EAASoJ,gBAAgBrJ,KAAK4D,QAAS5D,KAAKsJ,kBAAmBtJ,KAAK0H,cAIxF1H,KAAK4D,QAAQiK,SACd7N,KAAK4D,QAAQiK,QAAQ3M,QAAQ,SAAS4M,GACjCA,YAAkBjN,OACnBiN,EAAO,GAAG9N,KAAM8N,EAAO,IAEvBA,EAAO9N,OAETyN,KAAKzN,OAITA,KAAKgN,YAAYhN,KAAKqJ,gBAAgBI,iBACtCgE,KAAKzN,MAAO,GAIhBC,EAASqN,KAAOrN,EAASsL,MAAM7K,QAC7BqL,YAAauB,EACbjE,gBAAiBrG,OACjBlB,UAAWkB,OACXd,IAAKc,OACL0E,aAAc1E,OACdgK,YAAa,WACX,KAAM,IAAIZ,OAAM,2CAElBW,OAAQA,EACRE,OAAQA,EACRG,GAAIA,EACJC,IAAKA,EACLnN,QAASD,EAASC,QAClBgH,uBAAuB,KAGzB/G,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAuBA,SAASmC,GAAI2L,EAAM9G,EAAYhF,EAAW8E,EAAQiH,GAE7CD,YAAgBE,YACjBjO,KAAKyC,MAAQsL,GAEb/N,KAAKyC,MAAQrC,EAAS8N,gBAAgBC,EAAOJ,GAGjC,QAATA,GACD/N,KAAKyC,MAAM2L,eAAeC,EAAOpO,EAASoO,MAAMC,cAAerO,EAASoO,MAAME,KAG7EtH,GACDjH,KAAKqC,KAAK4E,GAGThF,GACDjC,KAAKsC,SAASL,GAGb8E,IACGiH,GAAejH,EAAOtE,MAAM+L,WAC9BzH,EAAOtE,MAAMgM,aAAazO,KAAKyC,MAAOsE,EAAOtE,MAAM+L,YAEnDzH,EAAOtE,MAAMD,YAAYxC,KAAKyC,SActC,QAASJ,GAAK4E,EAAYyH,GACxB,MAAyB,gBAAfzH,GACLyH,EACM1O,KAAKyC,MAAMkM,eAAeD,EAAIzH,GAE9BjH,KAAKyC,MAAMmM,aAAa3H,IAInCwE,OAAOoD,KAAK5H,GAAY/F,QAAQ,SAAS4N,GAEhB9L,SAApBiE,EAAW6H,KAIXJ,EACD1O,KAAKyC,MAAM2L,eAAeM,GAAKzO,EAASoO,MAAMU,OAAQ,IAAKD,GAAK3G,KAAK,IAAKlB,EAAW6H,IAErF9O,KAAKyC,MAAMuM,aAAaF,EAAK7H,EAAW6H,MAE1CrB,KAAKzN,OAEAA,MAaT,QAASqH,GAAK0G,EAAM9G,EAAYhF,EAAW+L,GACzC,MAAO,IAAI/N,GAASmC,IAAI2L,EAAM9G,EAAYhF,EAAWjC,KAAMgO,GAQ7D,QAASjH,KACP,MAAO/G,MAAKyC,MAAMwM,qBAAsBhB,YAAa,GAAIhO,GAASmC,IAAIpC,KAAKyC,MAAMwM,YAAc,KAQjG,QAASxP,KAEP,IADA,GAAIyP,GAAOlP,KAAKyC,MACQ,QAAlByM,EAAKC,UACTD,EAAOA,EAAKD,UAEd,OAAO,IAAIhP,GAASmC,IAAI8M,GAS1B,QAASxN,GAAc0N,GACrB,GAAIC,GAAYrP,KAAKyC,MAAMf,cAAc0N,EACzC,OAAOC,GAAY,GAAIpP,GAASmC,IAAIiN,GAAa,KASnD,QAASC,GAAiBF,GACxB,GAAIG,GAAavP,KAAKyC,MAAM6M,iBAAiBF,EAC7C,OAAOG,GAAWxM,OAAS,GAAI9C,GAASmC,IAAIoN,KAAKD,GAAc,KAajE,QAASnI,GAAcD,EAASF,EAAYhF,EAAW+L,GAGrD,GAAsB,gBAAZ7G,GAAsB,CAC9B,GAAIrF,GAAY1B,EAASqP,cAAc,MACvC3N,GAAU4N,UAAYvI,EACtBA,EAAUrF,EAAU0M,WAItBrH,EAAQ6H,aAAa,QAASW,EAI9B,IAAIC,GAAQ5P,KAAKqH,KAAK,gBAAiBJ,EAAYhF,EAAW+L,EAK9D,OAFA4B,GAAMnN,MAAMD,YAAY2E,GAEjByI,EAUT,QAAS5I,GAAK6I,GAEZ,MADA7P,MAAKyC,MAAMD,YAAYpC,EAAS0P,eAAeD,IACxC7P,KAST,QAAS+P,KACP,KAAO/P,KAAKyC,MAAM+L,YAChBxO,KAAKyC,MAAMN,YAAYnC,KAAKyC,MAAM+L,WAGpC,OAAOxO,MAST,QAASgQ,KAEP,MADAhQ,MAAKyC,MAAMwM,WAAW9M,YAAYnC,KAAKyC,OAChCzC,KAAK+G,SAUd,QAASxF,GAAQ0O,GAEf,MADAjQ,MAAKyC,MAAMwM,WAAWiB,aAAaD,EAAWxN,MAAOzC,KAAKyC,OACnDwN,EAWT,QAASE,GAAO3H,EAASwF,GAOvB,MANGA,IAAehO,KAAKyC,MAAM+L,WAC3BxO,KAAKyC,MAAMgM,aAAajG,EAAQ/F,MAAOzC,KAAKyC,MAAM+L,YAElDxO,KAAKyC,MAAMD,YAAYgG,EAAQ/F,OAG1BzC,KAST,QAASoQ,KACP,MAAOpQ,MAAKyC,MAAMmM,aAAa,SAAW5O,KAAKyC,MAAMmM,aAAa,SAASyB,OAAOC,MAAM,UAU1F,QAAShO,GAASiO,GAShB,MARAvQ,MAAKyC,MAAMuM,aAAa,QACtBhP,KAAKoQ,QAAQpQ,KAAKyC,OACf6J,OAAOiE,EAAMF,OAAOC,MAAM,QAC1BE,OAAO,SAASnJ,EAAMS,EAAK2I,GAC1B,MAAOA,GAAK1F,QAAQ1D,KAAUS,IAC7BK,KAAK,MAGLnI,KAUT,QAAS0Q,GAAYH,GACnB,GAAII,GAAiBJ,EAAMF,OAAOC,MAAM,MAMxC,OAJAtQ,MAAKyC,MAAMuM,aAAa,QAAShP,KAAKoQ,QAAQpQ,KAAKyC,OAAO+N,OAAO,SAASzC,GACxE,MAAwC,KAAjC4C,EAAe5F,QAAQgD,KAC7B5F,KAAK,MAEDnI,KAST,QAAS4Q,KAGP,MAFA5Q,MAAKyC,MAAMuM,aAAa,QAAS,IAE1BhP,KAUT,QAASgC,KACP,MAAOhC,MAAKyC,MAAMoO,cAAgBxN,KAAKiC,MAAMtF,KAAKyC,MAAMqO,UAAU9O,SAAWhC,KAAKyC,MAAMwM,WAAW4B,aAUrG,QAAS9O,KACP,MAAO/B,MAAKyC,MAAMsO,aAAe1N,KAAKiC,MAAMtF,KAAKyC,MAAMqO,UAAU/O,QAAU/B,KAAKyC,MAAMwM,WAAW8B,YA4CnG,QAASC,GAAQC,EAAYC,EAAQxJ,GA4GnC,MA3Gc1E,UAAXkO,IACDA,GAAS,GAGXzF,OAAOoD,KAAKoC,GAAY/P,QAAQ,SAAoCiQ,GAElE,QAASC,GAAcC,EAAqBH,GAC1C,GACEF,GACAM,EACAC,EAHEC,IAODH,GAAoBE,SAErBA,EAASF,EAAoBE,iBAAkB1Q,OAC7CwQ,EAAoBE,OACpBtR,EAASmC,IAAIqP,OAAOJ,EAAoBE,cACnCF,GAAoBE,QAI7BF,EAAoBK,MAAQzR,EAASuB,WAAW6P,EAAoBK,MAAO,MAC3EL,EAAoBM,IAAM1R,EAASuB,WAAW6P,EAAoBM,IAAK,MAEpEJ,IACDF,EAAoBO,SAAW,SAC/BP,EAAoBQ,WAAaN,EAAOpJ,KAAK,KAC7CkJ,EAAoBS,SAAW,OAI9BZ,IACDG,EAAoBU,KAAO,SAE3BP,EAAoBL,GAAaE,EAAoBW,KACrDhS,KAAKqC,KAAKmP,GAIVF,EAAUrR,EAASoB,UAAUgQ,EAAoBK,OAAS,GAC1DL,EAAoBK,MAAQ,cAG9BV,EAAUhR,KAAKqH,KAAK,UAAWpH,EAASS,QACtCuR,cAAed,GACdE,IAEAH,GAEDtD,WAAW,WAIT,IACEoD,EAAQvO,MAAMyP,eACd,MAAMC,GAENX,EAAoBL,GAAaE,EAAoBe,GACrDpS,KAAKqC,KAAKmP,GAEVR,EAAQhB,WAEVvC,KAAKzN,MAAOsR,GAGb5J,GACDsJ,EAAQvO,MAAMkL,iBAAiB,aAAc,WAC3CjG,EAAaU,KAAK,kBAChBI,QAASxI,KACTgR,QAASA,EAAQvO,MACjB4P,OAAQhB,KAEV5D,KAAKzN,OAGTgR,EAAQvO,MAAMkL,iBAAiB,WAAY,WACtCjG,GACDA,EAAaU,KAAK,gBAChBI,QAASxI,KACTgR,QAASA,EAAQvO,MACjB4P,OAAQhB,IAITH,IAEDM,EAAoBL,GAAaE,EAAoBe,GACrDpS,KAAKqC,KAAKmP,GAEVR,EAAQhB,WAEVvC,KAAKzN,OAINiR,EAAWE,YAAsBtQ,OAClCoQ,EAAWE,GAAWjQ,QAAQ,SAASmQ,GACrCD,EAAc3D,KAAKzN,MAAMqR,GAAqB,IAC9C5D,KAAKzN,OAEPoR,EAAc3D,KAAKzN,MAAMiR,EAAWE,GAAYD,IAGlDzD,KAAKzN,OAEAA,KA+ET,QAASsS,GAAQC,GACf,GAAIrH,GAAOlL,IAEXA,MAAKwS,cACL,KAAI,GAAI3P,GAAI,EAAGA,EAAI0P,EAASxP,OAAQF,IAClC7C,KAAKwS,YAAY7M,KAAK,GAAI1F,GAASmC,IAAImQ,EAAS1P,IAIlD4I,QAAOoD,KAAK5O,EAASmC,IAAItB,WAAW0P,OAAO,SAASiC,GAClD,MAQ4C,MARpC,cACJ,SACA,gBACA,mBACA,UACA,SACA,UACA,SACA,SAAS1H,QAAQ0H,KACpBvR,QAAQ,SAASuR,GAClBvH,EAAKuH,GAAqB,WACxB,GAAI/F,GAAO7L,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,EAIjD,OAHAiK,GAAKsH,YAAYtR,QAAQ,SAASsH,GAChCvI,EAASmC,IAAItB,UAAU2R,GAAmBzG,MAAMxD,EAASkE,KAEpDxB,KA9jBb,GAAIiD,GAAQ,6BACVE,EAAQ,gCACRsB,EAAU,8BAEZ1P,GAASoO,OACPC,cAAe,WACfS,OAAQ,KACRR,IAAK,6CAkdPtO,EAASmC,IAAMnC,EAASsL,MAAM7K,QAC5BqL,YAAa3J,EACbC,KAAMA,EACNgF,KAAMA,EACNN,OAAQA,EACRtH,KAAMA,EACNiC,cAAeA,EACf4N,iBAAkBA,EAClBlI,cAAeA,EACfJ,KAAMA,EACN+I,MAAOA,EACPC,OAAQA,EACRzO,QAASA,EACT4O,OAAQA,EACRC,QAASA,EACT9N,SAAUA,EACVoO,YAAaA,EACbE,iBAAkBA,EAClB5O,OAAQA,EACRD,MAAOA,EACPiP,QAASA,IAUX/Q,EAASmC,IAAImL,YAAc,SAASmF,GAClC,MAAOtS,GAASuS,eAAeC,WAAW,sCAAwCF,EAAS,OAQ7F,IAAIG,IACFC,YAAa,IAAM,EAAG,KAAO,MAC7BC,aAAc,IAAM,KAAO,KAAO,GAClCC,eAAgB,KAAO,IAAM,IAAM,KACnCC,YAAa,IAAM,KAAO,IAAM,KAChCC,aAAc,IAAM,IAAM,IAAM,KAChCC,eAAgB,KAAO,IAAM,KAAO,MACpCC,aAAc,IAAM,KAAO,KAAO,KAClCC,cAAe,KAAO,IAAM,KAAO,GACnCC,gBAAiB,KAAO,KAAO,KAAO,GACtCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,KAAO,IAAM,IAAM,GAClCC,gBAAiB,IAAM,EAAG,KAAO,GACjCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,IAAM,EAAG,IAAM,GAC9BC,gBAAiB,IAAM,EAAG,IAAM,GAChCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,IAAM,EAAG,IAAM,GAC7BC,eAAgB,EAAG,EAAG,EAAG,GACzBC,YAAa,GAAK,IAAM,IAAM,MAC9BC,aAAc,KAAO,IAAM,KAAO,GAClCC,eAAgB,KAAO,KAAO,IAAM,KACpCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,KAAO,KAAO,IAAM,OAClCC,eAAgB,KAAO,IAAM,KAAO,MAGtCpU,GAASmC,IAAIqP,OAASoB,EAwCtB5S,EAASmC,IAAIoN,KAAOvP,EAASsL,MAAM7K,QACjCqL,YAAauG,KAGfnS,OAAQC,SAAUH,GASnB,SAASE,EAAQC,EAAUH,GAC1B,YAiDA,SAAS+M,GAAYpJ,GACnB,GACED,GADE2Q,KAEF3P,EAAiB1E,EAASiD,mBAAmBjD,EAASyC,aAAa1C,KAAK2C,MAAO3C,KAAK2C,KAAK8E,OAAO1E,OAGlG/C,MAAKkC,IAAMjC,EAAS4B,UAAU7B,KAAK8B,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQqE,WAAWsM,OAGhG5Q,EAAS1D,EAASyE,UAAU1E,KAAKkC,IAAKyC,EAAgBf,EAEtD,IAAI2D,GAAYtH,EAASsG,gBAAgBvG,KAAKkC,IAAK0B,GAE/C6D,EAASzH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWuM,YAC1DhN,EAAOxH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWwM,UAExDxU,GAASqH,YAAYC,EAAWvH,KAAK2C,KAAM6E,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,uBAC1FjH,EAASiJ,YAAY3B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAI7C,KAAK2C,KAAKG,OAAOC,OAAQF,IAAK,CAChDyR,EAAazR,GAAK7C,KAAKkC,IAAImF,KAAK,KAG7BrH,KAAK2C,KAAKG,OAAOD,GAAGkL,MACrBuG,EAAazR,GAAGR,MACdqS,cAAe1U,KAAK2C,KAAKG,OAAOD,GAAGkL,MAClC9N,EAASoO,MAAME,KAIpB+F,EAAazR,GAAGP,UACdsB,EAAQqE,WAAWnF,OAClB9C,KAAK2C,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQqE,WAAWnF,OAAS,IAAM7C,EAASM,cAAcsC,IAC3FsF,KAAK,KAMP,KAAK,GAJDoC,GAEFoK,EADAC,KAGO3R,EAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAC5CsH,EAAItK,EAASmJ,aAAa7B,EAAW5D,EAAQgB,EAAe9B,GAAII,GAChE2R,EAAgBjP,KAAK4E,EAAEpE,EAAGoE,EAAElE,GAIxBzC,EAAQiR,YACVF,EAAQL,EAAazR,GAAGwE,KAAK,QAC3BX,GAAI6D,EAAEpE,EACNQ,GAAI4D,EAAElE,EACNO,GAAI2D,EAAEpE,EAAI,IACVU,GAAI0D,EAAElE,GACLzC,EAAQqE,WAAW0M,OAAOtS,MAC3Bf,MAASqD,EAAe9B,GAAGI,IAC1BhD,EAASoO,MAAME,KAElBvO,KAAK0H,aAAaU,KAAK,QACrBC,KAAM,QACN/G,MAAOqD,EAAe9B,GAAGI,GACzB0E,MAAO1E,EACPsF,MAAO+L,EAAazR,GACpB2F,QAASmM,EACTxO,EAAGoE,EAAEpE,EACLE,EAAGkE,EAAElE,IAMX,IAAIzC,EAAQkR,UAAYlR,EAAQmR,SAAU,CAExC,GAAIC,IAAgB,IAAMJ,EAAgB,GAAK,IAAMA,EAAgB,GAGrE,IAAIhR,EAAQqR,YAAcL,EAAgB7R,OAAS,EAGjD,IAAI,GADAmS,GAAKjV,EAASiK,kBAAkB0K,GAC5BO,EAAI,EAAGA,EAAID,EAAGnS,OAAQoS,IAC5BH,EAAarP,KAAK,IAAMuP,EAAGC,GAAGhN,YAGhC,KAAI,GAAIiN,GAAI,EAAGA,EAAIR,EAAgB7R,OAAQqS,GAAK,EAC9CJ,EAAarP,KAAK,IAAMiP,EAAgBQ,EAAI,GAAK,IAAMR,EAAgBQ,GAI3E,IAAGxR,EAAQmR,SAAU,CAGnB,GAAIM,GAAWhS,KAAKW,IAAIX,KAAK0B,IAAInB,EAAQyR,SAAU1R,EAAOK,KAAML,EAAOoB,KAGnEuQ,EAAmBN,EAAajU,QAGhCwU,EAAoBtV,EAASmJ,aAAa7B,EAAW5D,GAAS0R,GAAW,EAE7EC,GAAiBxK,OAAO,EAAG,EAAG,IAAMyK,EAAkBpP,EAAI,IAAMoP,EAAkBlP,GAClFiP,EAAiB,GAAK,IAAMV,EAAgB,GAAK,IAAMA,EAAgB,GACvEU,EAAiB3P,KAAK,IAAMiP,EAAgBA,EAAgB7R,OAAS,GAAK,IAAMwS,EAAkBlP,EAGlG,IAAImP,GAAOlB,EAAazR,GAAGwE,KAAK,QAC9BgD,EAAGiL,EAAiBnN,KAAK,KACxBvE,EAAQqE,WAAWuN,MAAM,GAAMnT,MAChCqD,OAAUf,EAAe9B,IACxB5C,EAASoO,MAAME,IAElBvO,MAAK0H,aAAaU,KAAK,QACrBC,KAAM,OACN3C,OAAQf,EAAe9B,GACvB8E,MAAO9E,EACP0F,MAAO+L,EAAazR,GACpB2F,QAASgN,IAIb,GAAG5R,EAAQkR,SAAU,CACnB,GAAIW,GAAOnB,EAAazR,GAAGwE,KAAK,QAC9BgD,EAAG2K,EAAa7M,KAAK,KACpBvE,EAAQqE,WAAWwN,MAAM,GAAMpT,MAChCqD,OAAUf,EAAe9B,IACxB5C,EAASoO,MAAME,IAElBvO,MAAK0H,aAAaU,KAAK,QACrBC,KAAM,OACN3C,OAAQf,EAAe9B,GACvB8E,MAAO9E,EACP0F,MAAO+L,EAAazR,GACpB2F,QAASiN,MAMjBzV,KAAK0H,aAAaU,KAAK,WACrBzE,OAAQA,EACR4D,UAAWA,EACXrF,IAAKlC,KAAKkC,IACV0B,QAASA,IAgJb,QAAS8R,GAAK/T,EAAOgB,EAAMiB,EAAS0F,GAClCrJ,EAASyV,KAAKzJ,MAAMF,YAAY/K,KAAKhB,KACnC2B,EACAgB,EACA1C,EAASS,UAAWiV,EAAgB/R,GACpC0F,GAhVJ,GAAIqM,IACFzR,OACEC,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,MAElCmF,OACErB,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,KAChCoF,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACR8R,UAAU,EACVD,WAAW,EACXE,UAAU,EACVM,SAAU,EACVJ,YAAY,EACZxQ,IAAKzB,OACLsB,KAAMtB,OACNiB,aAAc,EACdgE,YACEsM,MAAO,gBACP1L,MAAO,WACP2L,WAAY,YACZ1R,OAAQ,YACR2S,KAAM,UACNd,MAAO,WACPa,KAAM,UACNhO,KAAM,UACNiN,UAAW,WACXtL,SAAU,cACVjB,WAAY,iBAyShBjI,GAASyV,KAAOzV,EAASqN,KAAK5M,QAC5BqL,YAAa2J,EACb1I,YAAaA,KAGf7M,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA2CA,SAAS+M,GAAYpJ,GACnB,GACED,GADE2Q,KAEF3P,EAAiB1E,EAASiD,mBAAmBjD,EAASyC,aAAa1C,KAAK2C,MAAO3C,KAAK2C,KAAK8E,OAAO1E,OAGlG/C,MAAKkC,IAAMjC,EAAS4B,UAAU7B,KAAK8B,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQqE,WAAWsM,OAGhG5Q,EAAS1D,EAASyE,UAAU1E,KAAKkC,IAAKyC,EAAgBf,EAAS,EAE/D,IAAI2D,GAAYtH,EAASsG,gBAAgBvG,KAAKkC,IAAK0B,GAE/C6D,EAASzH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWuM,YAC1DhN,EAAOxH,KAAKkC,IAAImF,KAAK,KAAK/E,SAASsB,EAAQqE,WAAWwM,WAEtDmB,EAAY3V,EAASmJ,aAAa7B,EAAW5D,GAAS,GAAI,EAE5D1D,GAASqH,YAAYC,EAAWvH,KAAK2C,KAAM6E,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,uBAC1FjH,EAASiJ,YAAY3B,EAAW5D,EAAQ6D,EAAMC,EAAQ7D,EAAS5D,KAAK0H,aAAc1H,KAAKkH,sBAIvF,KAAK,GAAIrE,GAAI,EAAGA,EAAI7C,KAAK2C,KAAKG,OAAOC,OAAQF,IAAK,CAEhD,GAAIgT,GAAQhT,GAAK7C,KAAK2C,KAAKG,OAAOC,OAAS,GAAK,EAE9C+S,EAAkBvO,EAAUxF,QAAU4C,EAAe9B,GAAGE,OAAS,CAEnEuR,GAAazR,GAAK7C,KAAKkC,IAAImF,KAAK,KAG7BrH,KAAK2C,KAAKG,OAAOD,GAAGkL,MACrBuG,EAAazR,GAAGR,MACdqS,cAAe1U,KAAK2C,KAAKG,OAAOD,GAAGkL,MAClC9N,EAASoO,MAAME,KAIpB+F,EAAazR,GAAGP,UACdsB,EAAQqE,WAAWnF,OAClB9C,KAAK2C,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQqE,WAAWnF,OAAS,IAAM7C,EAASM,cAAcsC,IAC3FsF,KAAK,KAEP,KAAI,GAAIlF,GAAI,EAAGA,EAAI0B,EAAe9B,GAAGE,OAAQE,IAAK,CAChD,GACE8S,GADExL,EAAItK,EAASmJ,aAAa7B,EAAW5D,EAAQgB,EAAe9B,GAAII,EAKpEsH,GAAEpE,GAAK2P,EAAmBD,EAAQjS,EAAQoS,kBAE1CD,EAAMzB,EAAazR,GAAGwE,KAAK,QACzBX,GAAI6D,EAAEpE,EACNQ,GAAIiP,EAAUvP,EACdO,GAAI2D,EAAEpE,EACNU,GAAI0D,EAAElE,GACLzC,EAAQqE,WAAW8N,KAAK1T,MACzBf,MAASqD,EAAe9B,GAAGI,IAC1BhD,EAASoO,MAAME,KAElBvO,KAAK0H,aAAaU,KAAK,QACrBC,KAAM,MACN/G,MAAOqD,EAAe9B,GAAGI,GACzB0E,MAAO1E,EACPsF,MAAO+L,EAAazR,GACpB2F,QAASuN,EACTrP,GAAI6D,EAAEpE,EACNQ,GAAIiP,EAAUvP,EACdO,GAAI2D,EAAEpE,EACNU,GAAI0D,EAAElE,KAKZrG,KAAK0H,aAAaU,KAAK,WACrBzE,OAAQA,EACR4D,UAAWA,EACXrF,IAAKlC,KAAKkC,IACV0B,QAASA,IAwGb,QAASqS,GAAItU,EAAOgB,EAAMiB,EAAS0F,GACjCrJ,EAASgW,IAAIhK,MAAMF,YAAY/K,KAAKhB,KAClC2B,EACAgB,EACA1C,EAASS,UAAWiV,EAAgB/R,GACpC0F,GArOJ,GAAIqM,IACFzR,OACEC,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,MAElCmF,OACErB,OAAQ,GACRwE,aACExC,EAAG,EACHE,EAAG,GAELoC,WAAW,EACXV,UAAU,EACVF,sBAAuB5H,EAASI,KAChCoF,cAAe,IAEjB1D,MAAOiB,OACPhB,OAAQgB,OACRsB,KAAMtB,OACNyB,IAAKzB,OACLiB,aAAc,EACd+R,kBAAmB,GACnB/N,YACEsM,MAAO,eACP1L,MAAO,WACP2L,WAAY,YACZ1R,OAAQ,YACRiT,IAAK,SACLvO,KAAM,UACNiN,UAAW,WACXtL,SAAU,cACVjB,WAAY,iBAoMhBjI,GAASgW,IAAMhW,EAASqN,KAAK5M,QAC3BqL,YAAakK,EACbjJ,YAAaA,KAGf7M,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAwBA,SAASiW,GAAwBC,EAAQtN,EAAOuN,GAC9C,GAAIC,GAAaxN,EAAM1C,EAAIgQ,EAAOhQ,CAElC,OAAGkQ,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SAIX,QAASpJ,GAAYpJ,GACnB,GACE2D,GACAxB,EACAuQ,EACAC,EAJEjC,KAKFkC,EAAa5S,EAAQ4S,WACrBrT,EAAYlD,EAASyC,aAAa1C,KAAK2C,KAGzC3C,MAAKkC,IAAMjC,EAAS4B,UAAU7B,KAAK8B,UAAW8B,EAAQ7B,MAAO6B,EAAQ5B,OAAQ4B,EAAQqE,WAAWsM,OAEhGhN,EAAYtH,EAASsG,gBAAgBvG,KAAKkC,IAAK0B,EAAS,EAAG,GAE3DmC,EAAS1C,KAAK0B,IAAIwC,EAAUxF,QAAU,EAAGwF,EAAUvF,SAAW,GAE9DuU,EAAe3S,EAAQ6S,OAAStT,EAAUuT,OAAO,SAASC,EAAeC,GACvE,MAAOD,GAAgBC,GACtB,GAKH7Q,GAAUnC,EAAQiT,MAAQjT,EAAQkT,WAAa,EAAK,EAIpDR,EAAc1S,EAAQiT,MAAQ9Q,EAASA,EAAS,EAEhDuQ,GAAe1S,EAAQ+E,WAevB,KAAK,GAZDwN,IACFhQ,EAAGoB,EAAUb,GAAKa,EAAUxF,QAAU,EACtCsE,EAAGkB,EAAUV,GAAKU,EAAUvF,SAAW,GAIrC+U,EAEU,IAFa/W,KAAK2C,KAAKG,OAAO0N,OAAO,SAASwG,GAC1D,MAAe,KAARA,IACNjU,OAIMF,EAAI,EAAGA,EAAI7C,KAAK2C,KAAKG,OAAOC,OAAQF,IAAK,CAChDyR,EAAazR,GAAK7C,KAAKkC,IAAImF,KAAK,IAAK,KAAM,MAAM,GAG9CrH,KAAK2C,KAAKG,OAAOD,GAAGkL,MACrBuG,EAAazR,GAAGR,MACdqS,cAAe1U,KAAK2C,KAAKG,OAAOD,GAAGkL,MAClC9N,EAASoO,MAAME,KAIpB+F,EAAazR,GAAGP,UACdsB,EAAQqE,WAAWnF,OAClB9C,KAAK2C,KAAKG,OAAOD,GAAGZ,WAAa2B,EAAQqE,WAAWnF,OAAS,IAAM7C,EAASM,cAAcsC,IAC3FsF,KAAK,KAEP,IAAI8O,GAAWT,EAAarT,EAAUN,GAAK0T,EAAe,GAGvDU,GAAWT,IAAe,MAC3BS,GAAY,IAGd,IAAIC,GAAQjX,EAAS2F,iBAAiBuQ,EAAOhQ,EAAGgQ,EAAO9P,EAAGN,EAAQyQ,GAAoB,IAAN3T,GAAWkU,EAAuB,EAAI,KACpHI,EAAMlX,EAAS2F,iBAAiBuQ,EAAOhQ,EAAGgQ,EAAO9P,EAAGN,EAAQkR,GAC5DG,EAAoC,KAAzBH,EAAWT,EAAoB,IAAM,IAChDnM,GAEE,IAAK8M,EAAIhR,EAAGgR,EAAI9Q,EAEhB,IAAKN,EAAQA,EAAQ,EAAGqR,EAAU,EAAGF,EAAM/Q,EAAG+Q,EAAM7Q,EAIrDzC,GAAQiT,SAAU,GACnBxM,EAAE1E,KAAK,IAAKwQ,EAAOhQ,EAAGgQ,EAAO9P,EAK/B,IAAIgR,GAAO/C,EAAazR,GAAGwE,KAAK,QAC9BgD,EAAGA,EAAElC,KAAK,MACTvE,EAAQqE,WAAWlH,OAAS6C,EAAQiT,MAAQ,IAAMjT,EAAQqE,WAAW4O,MAAQ,IA6BhF,IA1BAQ,EAAKhV,MACHf,MAAS6B,EAAUN,IAClB5C,EAASoO,MAAME,KAGf3K,EAAQiT,SAAU,GACnBQ,EAAKhV,MACHE,MAAS,mBAAqBqB,EAAQkT,WAAc,OAKxD9W,KAAK0H,aAAaU,KAAK,QACrBC,KAAM,QACN/G,MAAO6B,EAAUN,GACjB0T,aAAcA,EACd5O,MAAO9E,EACP0F,MAAO+L,EAAazR,GACpB2F,QAAS6O,EACTlB,OAAQA,EACRpQ,OAAQA,EACRyQ,WAAYA,EACZS,SAAUA,IAITrT,EAAQ6E,UAAW,CAEpB,GAAIC,GAAgBzI,EAAS2F,iBAAiBuQ,EAAOhQ,EAAGgQ,EAAO9P,EAAGiQ,EAAaE,GAAcS,EAAWT,GAAc,GACpH5O,EAAoBhE,EAAQiE,sBAAsB7H,KAAK2C,KAAK8E,OAASzH,KAAK2C,KAAK8E,OAAO5E,GAAKM,EAAUN,GAAIA,GAEvG+F,EAAe0L,EAAazR,GAAGwE,KAAK,QACtCiQ,GAAI5O,EAAcvC,EAClBoR,GAAI7O,EAAcrC,EAClBmR,cAAetB,EAAwBC,EAAQzN,EAAe9E,EAAQ6T,iBACrE7T,EAAQqE,WAAWY,OAAO7B,KAAK,GAAKY,EAGvC5H,MAAK0H,aAAaU,KAAK,QACrBC,KAAM,QACNV,MAAO9E,EACP0F,MAAO+L,EAAazR,GACpB2F,QAASI,EACT5B,KAAM,GAAKY,EACXzB,EAAGuC,EAAcvC,EACjBE,EAAGqC,EAAcrC,IAMrBmQ,EAAaS,EAGfjX,KAAK0H,aAAaU,KAAK,WACrBb,UAAWA,EACXrF,IAAKlC,KAAKkC,IACV0B,QAASA,IAmGb,QAAS8T,GAAI/V,EAAOgB,EAAMiB,EAAS0F,GACjCrJ,EAASyX,IAAIzL,MAAMF,YAAY/K,KAAKhB,KAClC2B,EACAgB,EACA1C,EAASS,UAAWiV,EAAgB/R,GACpC0F,GA9RJ,GAAIqM,IACF5T,MAAOiB,OACPhB,OAAQgB,OACRiB,aAAc,EACdgE,YACEsM,MAAO,eACPzR,OAAQ,YACR/B,MAAO,WACP8V,MAAO,WACPhO,MAAO,YAET2N,WAAY,EACZC,MAAOzT,OACP6T,OAAO,EACPC,WAAY,GACZrO,WAAW,EACXE,YAAa,EACbd,sBAAuB5H,EAASI,KAChCsX,eAAe,EACfF,eAAgB,UA+QlBxX,GAASyX,IAAMzX,EAASqN,KAAK5M,QAC3BqL,YAAa2L,EACb1K,YAAaA,EACbkJ,wBAAyBA,KAG3B/V,OAAQC,SAAUH,GAEbA","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.4.4\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.4.4'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Array} The array that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\n };\n\n // Find the highest and lowest values in a two dimensional array and calculate scale based on order of magnitude\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Array} normalizedData The array that got updated with missing values.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, normalizedData, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = Chartist.getHighLow(normalizedData);\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / data.labels.length,\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index) {\n return {\n x: chartRect.x1 + chartRect.width() / data.length * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update() {\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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 /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 window.addEventListener('resize', this.resizeListener);\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 setTimeout(function() {\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\n }.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n showLine: true,\n showPoint: true,\n showArea: false,\n areaBase: 0,\n lineSmooth: true,\n low: undefined,\n high: undefined,\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the line chart\n * var options = {\n * // Options for X-Axis\n * axisX: {\n * // The offset of the labels to the chart area\n * offset: 30,\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: function(value){return value;}\n * },\n * // Options for Y-Axis\n * axisY: {\n * // The offset of the labels to the chart area\n * offset: 40,\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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 (Catmull-Rom-Splines will be used)\n * lineSmooth: true,\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\n * chartPadding: 5,\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 * // 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 adition 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 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 var defaultOptions = {\n axisX: {\n offset: 30,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop\n },\n axisY: {\n offset: 40,\n labelOffset: {\n x: 0,\n y: 0\n },\n showLabel: true,\n showGrid: true,\n labelInterpolationFnc: Chartist.noop,\n scaleMinSpace: 20\n },\n width: undefined,\n height: undefined,\n high: undefined,\n low: undefined,\n chartPadding: 5,\n seriesBarDistance: 15,\n classNames: {\n chart: 'ct-chart-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, normalizedData, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period with between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / normalizedData[i].length / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j),\n bar;\n\n // Offset to center bar between grid lines and using bi-polar offset for multiple series\n // TODO: Check if we should really be able to add classes to the series. Should be handles with Sass and semantic / specific selectors\n p.x += periodHalfWidth + (biPol * options.seriesBarDistance);\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: zeroPoint.y,\n x2: p.x,\n y2: p.y\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // These are the default options of the bar chart\n * var options = {\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 * // 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: function(value){return value;}\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 * // 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: function(value){return value;},\n * // This value specifies the minimum height in pixel of the scale steps\n * scaleMinSpace: 30\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 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\n * chartPadding: 5,\n * // Specify the distance in pixel of bars in a group\n * seriesBarDistance: 15,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-bar',\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 * vertical: 'ct-vertical',\n * horizontal: 'ct-horizontal'\n * }\n * };\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 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 var defaultOptions = {\n width: undefined,\n height: undefined,\n chartPadding: 5,\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-donut',\n label: 'ct-label'\n },\n startAngle: 0,\n total: undefined,\n donut: false,\n donutWidth: 60,\n showLabel: true,\n labelOffset: 0,\n labelInterpolationFnc: Chartist.noop,\n labelOverflow: false,\n labelDirection: 'neutral'\n };\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 function createChart(options) {\n var seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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 * // Default options of the pie chart\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\n * chartPadding: 5,\n * // Override the class names that get used to generate the SVG structure of the chart\n * classNames: {\n * chart: 'ct-chart-pie',\n * series: 'ct-series',\n * slice: 'ct-slice',\n * donut: 'ct-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 * 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 * // An interpolation function for the label value\n * labelInterpolationFnc: function(value, index) {return value;},\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 * };\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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":20439,"pos":20434,"col":16,"line":552,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":20439,"pos":20434,"col":16,"line":552,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","initializeTimeoutId","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","stackBars","serialSums","reduce","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.5.0\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.5.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update(data) {\n this.data = data || this.data;\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index c33093c1..20a4b1f5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.4.4", + "version": "0.5.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index 6770fc2b..697d5b17 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.4.4' + version: '0.5.0' }; (function (window, document, Chartist) { From 7fee1be923a0d45d63a9a2c1fab246444c53ba84 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 15 Dec 2014 00:03:18 +0100 Subject: [PATCH 133/593] Changed base styles of doc site --- site/styles/_base.scss | 8 +++----- site/styles/_live-example.scss | 4 ++-- site/styles/settings/_foundation.scss | 6 +++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/site/styles/_base.scss b/site/styles/_base.scss index 7e23e031..0fe3a99d 100644 --- a/site/styles/_base.scss +++ b/site/styles/_base.scss @@ -49,10 +49,6 @@ h1, h2, h3, h4, h5, h6 { line-height: 1.2; margin-top: 1em; margin-bottom: 0.5em; - - &:first-child { - margin-top: 0; - } } h2 { @@ -68,10 +64,12 @@ h2 { h3 { font-size: rem-calc(nth($modular-scale, 5)); font-weight: 400; + background: #ded0ba; + padding: 0.2em; + box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1); @media #{$medium-up} { font-size: rem-calc(nth($modular-scale, 7)); - font-weight: 300; } } diff --git a/site/styles/_live-example.scss b/site/styles/_live-example.scss index bb3eae43..7c532a7e 100644 --- a/site/styles/_live-example.scss +++ b/site/styles/_live-example.scss @@ -1,7 +1,7 @@ .live-example { @include grid-row(nest); - margin-bottom: rem-calc(nth($modular-scale, 8)); + margin-bottom: rem-calc(nth($modular-scale, 4)); &.edit-mode { .chart { @@ -54,4 +54,4 @@ fill: rgba(255, 255, 255, 0.8); } } -} \ No newline at end of file +} diff --git a/site/styles/settings/_foundation.scss b/site/styles/settings/_foundation.scss index 01d5026b..23fcd60f 100644 --- a/site/styles/settings/_foundation.scss +++ b/site/styles/settings/_foundation.scss @@ -1370,15 +1370,15 @@ $topbar-title-font-size: rem-calc(17); // Style the top bar dropdown elements $topbar-dropdown-bg: $color-gray; -$topbar-dropdown-link-color: #fff; +$topbar-dropdown-link-color: #f7f2ea; $topbar-dropdown-link-bg: $color-gray; $topbar-dropdown-link-weight: normal; $topbar-dropdown-toggle-size: 5px; -$topbar-dropdown-toggle-color: #fff; +$topbar-dropdown-toggle-color: #f7f2ea; $topbar-dropdown-toggle-alpha: 0.4; // Set the link colors and styles for top-level nav -$topbar-link-color: #fff; +$topbar-link-color: #f7f2ea; $topbar-link-color-hover: #fff; $topbar-link-color-active: #fff; $topbar-link-color-active-hover: #fff; From 42c0bc38d07e0530e0ee1dfce3a4700ebcf1b7f2 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 15 Dec 2014 00:04:08 +0100 Subject: [PATCH 134/593] Added plugins to documentation site and refactored styling and structure of the plugins page --- bower.json | 4 ++- site/data/pages/plugins.yml | 51 ++++++++++++++++++++++++++++++---- site/layouts/default.hbs | 4 +++ site/partials/live-example.hbs | 10 ++++--- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/bower.json b/bower.json index 97b11ce8..b3220057 100644 --- a/bower.json +++ b/bower.json @@ -11,7 +11,9 @@ "highlightjs": "~8.3.0", "compass-mixins": "~1.0.2", "codemirror": "~4.8.0", - "base64": "~0.3.0" + "base64": "~0.3.0", + "chartist-plugin-pointlabels": "~0.0.2", + "chartist-plugin-sketchy": "~0.0.1" }, "ignore": [ ".*", diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 15dfbc9b..458a44da 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -22,7 +22,7 @@ sections: data: text: > Once you have included a plugin in your project you can use it in your chart by specifying it explicitly - in the plugins section of your chart configuration. Check the List of plugins + in the plugins section of your chart configuration. Check the List of plugins section to see what plugins you can use. - type: code-snippet @@ -57,18 +57,57 @@ sections: - type: sub-section data: - title: List of Plugins + title: Point Label Plugin level: 4 items: + - type: text + data: + text: > + The point label plugin can be used if you like to add simple labels on top of your data points + on line charts. This is usefull if you'd like the user to see the exact values of the data without + any additional interaction. + - type: live-example + data: + id: example-plugin-pointlabel + classes: ct-golden-section + intro: > + The point label plugin draws labels on top of your line chart points. - type: table data: - id: chartist-plugin-list - header: - - Name and link rows: - - - chartist-plugin-pointlabels + - 'Author:' + - Gion Kunz + - + - 'Link:' + - 'chartist-plugin-pointlabels' + - type: sub-section + data: + title: Sketchy Plugin + level: 4 + items: + - type: text + data: + text: > + The sketchy plugin makes your charts look like they have been drawn by hand. This plugin makes use + of SVG filters and works on IE10+, Safari 7+ and Android 4.4+. Also note that SVG filters are not + very performant and they will eat your users mobile battery quickly for sure. + - type: live-example + data: + id: example-plugin-sketchy + classes: ct-golden-section + intro: > + Create beautiful hand drawn charts using the Chartist Sketchy plugin. + - type: table + data: + rows: + - + - 'Author:' + - Gion Kunz + - + - 'Link:' + - 'chartist-plugin-sketchy' - title: Develop a plugin level: 3 items: diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 4fa7d444..cf03565d 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -60,6 +60,10 @@ + + + + diff --git a/site/partials/live-example.hbs b/site/partials/live-example.hbs index 73062e28..18b56185 100644 --- a/site/partials/live-example.hbs +++ b/site/partials/live-example.hbs @@ -1,8 +1,10 @@ -
    -
    - {{title}} -
    + {{#if title}} +
    + {{title}} +
    + {{/if}}
    From adf4a83759040c53d6dbba98e8eda87b02c3e064 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 15 Dec 2014 00:04:45 +0100 Subject: [PATCH 135/593] Added plugin example files for doc site --- site/examples/example-plugin-pointlabel.js | 12 +++++++ site/examples/example-plugin-sketchy.js | 37 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 site/examples/example-plugin-pointlabel.js create mode 100644 site/examples/example-plugin-sketchy.js diff --git a/site/examples/example-plugin-pointlabel.js b/site/examples/example-plugin-pointlabel.js new file mode 100644 index 00000000..09b6768a --- /dev/null +++ b/site/examples/example-plugin-pointlabel.js @@ -0,0 +1,12 @@ +new Chartist.Line('.ct-chart', { + labels: ['M', 'T', 'W', 'T', 'F'], + series: [ + [12, 9, 7, 8, 5] + ] +}, { + plugins: [ + Chartist.plugins.ctPointLabels({ + textAnchor: 'middle' + }) + ] +}); diff --git a/site/examples/example-plugin-sketchy.js b/site/examples/example-plugin-sketchy.js new file mode 100644 index 00000000..35609901 --- /dev/null +++ b/site/examples/example-plugin-sketchy.js @@ -0,0 +1,37 @@ +new Chartist.Bar('.ct-chart', { + labels: ['Q1', 'Q2', 'Q3', 'Q4'], + series: [ + [800000, 1200000, 1400000, 1300000], + [200000, 400000, 500000, 300000], + [100000, 200000, 400000, 600000] + ] +}, { + plugins: [ + Chartist.plugins.ctSketchy({ + overrides: { + grid: { + baseFrequency: 0.2, + scale: 5, + numOctaves: 1 + }, + bar: { + baseFrequency: 0.02, + scale: 10 + }, + label: false + } + }) + ], + stackBars: true, + axisY: { + labelInterpolationFnc: function(value) { + return (value / 1000) + 'k'; + } + } +}).on('draw', function(data) { + if(data.type === 'bar') { + data.element.attr({ + style: 'stroke-width: 30px' + }); + } +}); From 677d52acb7b62332501de24e4aa7858ce551836a Mon Sep 17 00:00:00 2001 From: Christian Seel Date: Thu, 8 Jan 2015 17:15:05 +0100 Subject: [PATCH 136/593] Add options param to update() to extend options This little addition makes it possible to extend the options with the update() function. This is useful if you need to change the labelInterpolationFnc together with changed data. Tested in my current project without issues. --- src/scripts/base.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index 12637775..6d2de3ad 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -17,10 +17,15 @@ * Updates the chart which currently does a full reconstruction of the SVG DOM * * @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. + * @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. * @memberof Chartist.Base */ - function update(data) { + function update(data, options) { this.data = data || this.data; + if (typeof options !== 'undefined') { + this.options = Chartist.extend({}, this.options, options); + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + } this.createChart(this.optionsProvider.currentOptions); return this; } From 5479e61e422852081c85bf9cfe53e7d25686a965 Mon Sep 17 00:00:00 2001 From: Tyler Gaw Date: Thu, 8 Jan 2015 21:17:09 -0500 Subject: [PATCH 137/593] Adds ember-cli-chartist to Projects list --- site/data/pages/index.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index c03040f3..35c7b59a 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -228,6 +228,9 @@ sections: - - 'tablepress_chartist' - Wordpress / Tablepress Extension + - + - 'ember-cli-chartist' + - Ember Addon - title: Chart CSS animation example level: 3 items: From 8b500a27b9bfffb429937771e9efd4226e0a65ff Mon Sep 17 00:00:00 2001 From: Christian Seel Date: Fri, 9 Jan 2015 15:18:08 +0100 Subject: [PATCH 138/593] added removeMediaQueryListeners --- src/scripts/base.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scripts/base.js b/src/scripts/base.js index 6d2de3ad..f13c2df1 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -24,6 +24,7 @@ this.data = data || this.data; if (typeof options !== 'undefined') { this.options = Chartist.extend({}, this.options, options); + this.optionsProvider.removeMediaQueryListeners(); this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); } this.createChart(this.optionsProvider.currentOptions); From 5c5d734046abb896120a493a7d071ff417a06047 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 12 Jan 2015 12:01:58 +0200 Subject: [PATCH 139/593] bower ignore: add "tasks" --- bower.json | 1 + 1 file changed, 1 insertion(+) diff --git a/bower.json b/bower.json index b3220057..0a68b847 100644 --- a/bower.json +++ b/bower.json @@ -18,6 +18,7 @@ "ignore": [ ".*", "Gruntfile.js", + "tasks", "package.json", "node_modules", "public", From 551d24433a3f643100d69e22607b84edb21a0260 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 12 Jan 2015 12:05:38 +0200 Subject: [PATCH 140/593] bower ignore: add "site" --- bower.json | 1 + 1 file changed, 1 insertion(+) diff --git a/bower.json b/bower.json index b3220057..60f5565a 100644 --- a/bower.json +++ b/bower.json @@ -21,6 +21,7 @@ "package.json", "node_modules", "public", + "site", "src", "test" ] From 6f31664c3d4ce3deef2402d655bad308bb90055d Mon Sep 17 00:00:00 2001 From: Tyler Gaw Date: Wed, 14 Jan 2015 18:58:32 -0500 Subject: [PATCH 141/593] Include jQuery in Jasmine specs --- tasks/jasmine.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks/jasmine.js b/tasks/jasmine.js index 1d467673..a35640bf 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -25,6 +25,9 @@ module.exports = function (grunt) { options: { specs: '<%= pkg.config.test %>/spec/**/spec-*.js', helpers: '<%= pkg.config.test %>/spec/**/helper-*.js', + vendor: [ + 'http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js' + ], phantomjs: { 'ignore-ssl-errors': true } From c5af2348efebe3670f2add3ee233a3b500e5a4c3 Mon Sep 17 00:00:00 2001 From: Tyler Gaw Date: Wed, 14 Jan 2015 18:59:02 -0500 Subject: [PATCH 142/593] Add core spec and failing test for createSvg --- test/spec/spec-core.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/spec/spec-core.js diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js new file mode 100644 index 00000000..d0d25b4b --- /dev/null +++ b/test/spec/spec-core.js @@ -0,0 +1,28 @@ +describe('Chartist core', function() { + 'use strict'; + + beforeEach(function() { + + }); + + afterEach(function() { + + }); + + describe('createSvg tests', function () { + it('should not remove non-chartist svg elements', function() { + $('body').append('
    '); + + var container = $('#chart-container'), + childSvg = $('#chart-container #foo'), + nestedChildSvg = $('#chart-container #bar'), + + // We use get(0) because we want the DOMElement, not the jQuery object. + svg = Chartist.createSvg(container.get(0), '500px', '400px', 'ct-fish-bar'); + + expect(svg).toBeDefined(); + expect(childSvg.length).toEqual(1); + expect(nestedChildSvg.length).toEqual(1); + }); + }); +}); From 10ff8b8bbd493f6f58aff3e15738a335aa99b860 Mon Sep 17 00:00:00 2001 From: Tyler Gaw Date: Wed, 14 Jan 2015 19:00:01 -0500 Subject: [PATCH 143/593] Specify svg className so only chartist svg element is found and removed --- src/scripts/core.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 697d5b17..c930d811 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -164,8 +164,10 @@ var Chartist = { width = width || '100%'; height = height || '100%'; - svg = container.querySelector('svg'); - if(svg) { + // Append the className so we only remove the Chartist svg element, not + // any other svg elements in the container. + svg = container.querySelector('svg.' + className); + if (svg) { container.removeChild(svg); } From c2eed8467f5bfaf547aba90c47b918c66856ee27 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 15 Jan 2015 11:17:21 +0100 Subject: [PATCH 144/593] Added jasmine-jquery for better matchers and fixture handling --- package.json | 2 +- tasks/jasmine.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 20a4b1f5..6ae6a70d 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "grunt-umd": "~2.2.1", "grunt-usemin": "~2.6.2", "handlebars-helpers": "~0.5.8", - "jasmine-fixture": "~1.2.2", + "jasmine-jquery": "~2.0.5", "jshint-stylish": "~1.0.0", "load-grunt-config": "^0.16.0", "lodash": "^2.4.1", diff --git a/tasks/jasmine.js b/tasks/jasmine.js index a35640bf..6f33c8d6 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -26,7 +26,8 @@ module.exports = function (grunt) { specs: '<%= pkg.config.test %>/spec/**/spec-*.js', helpers: '<%= pkg.config.test %>/spec/**/helper-*.js', vendor: [ - 'http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js' + 'http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', + 'node_modules/jasmine-jquery/lib/jasmine-jquery.js' ], phantomjs: { 'ignore-ssl-errors': true From 95726f11f028004f79159b41aa92671c3714e7b2 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 15 Jan 2015 11:18:37 +0100 Subject: [PATCH 145/593] Changed from class selector to Chartist namespace filtering to recycle SVG elements --- src/scripts/core.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index c930d811..127d47b9 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -164,12 +164,13 @@ var Chartist = { width = width || '100%'; height = height || '100%'; - // Append the className so we only remove the Chartist svg element, not - // any other svg elements in the container. - svg = container.querySelector('svg.' + className); - if (svg) { + // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it + // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ + Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { + return svg.getAttribute(Chartist.xmlNs.qualifiedName); + }).forEach(function removePreviousElement(svg) { container.removeChild(svg); - } + }); // Create svg object with width and height or use 100% as default svg = new Chartist.Svg('svg').attr({ From b9e6853a5b2dec7d69344a26383293a6b9847ed2 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 15 Jan 2015 11:25:02 +0100 Subject: [PATCH 146/593] Updated tests for createSvg --- test/spec/spec-core.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index d0d25b4b..ffa6147f 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -11,18 +11,32 @@ describe('Chartist core', function() { describe('createSvg tests', function () { it('should not remove non-chartist svg elements', function() { - $('body').append('
    '); + jasmine.getFixtures().set('
    '); var container = $('#chart-container'), - childSvg = $('#chart-container #foo'), - nestedChildSvg = $('#chart-container #bar'), - // We use get(0) because we want the DOMElement, not the jQuery object. svg = Chartist.createSvg(container.get(0), '500px', '400px', 'ct-fish-bar'); expect(svg).toBeDefined(); - expect(childSvg.length).toEqual(1); - expect(nestedChildSvg.length).toEqual(1); + expect(svg.classes()).toContain('ct-fish-bar'); + expect(container).toContainElement('#foo'); + expect(container).toContainElement('#bar'); + }); + + it('should remove previous chartist svg elements', function() { + jasmine.getFixtures().set('
    '); + + var container = $('#chart-container'), + // We use get(0) because we want the DOMElement, not the jQuery object. + svg1 = Chartist.createSvg(container.get(0), '500px', '400px', 'ct-fish-bar'), + svg2 = Chartist.createSvg(container.get(0), '800px', '200px', 'ct-snake-bar'); + + expect(svg1).toBeDefined(); + expect(svg1.classes()).toContain('ct-fish-bar'); + expect(svg2).toBeDefined(); + expect(svg2.classes()).toContain('ct-snake-bar'); + expect(container).not.toContainElement('.ct-fish-bar'); + expect(container).toContainElement('.ct-snake-bar'); }); }); }); From aad8067da98fafdc3ff8990ec9bb8320f4bfec77 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 16 Jan 2015 22:24:13 +0100 Subject: [PATCH 147/593] Added 14 default series colors, fixes #124 --- src/styles/settings/_chartist-settings.scss | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss index 059e3d8a..b244b592 100644 --- a/src/styles/settings/_chartist-settings.scss +++ b/src/styles/settings/_chartist-settings.scss @@ -61,5 +61,21 @@ $ct-include-colored-series: $ct-include-classes !default; $ct-include-alternative-responsive-containers: $ct-include-classes !default; // Series names and colors. This can be extended or customized as desired. Just add more series and colors. -$ct-series-names: (a, b, c, d) !default; -$ct-series-colors: (#d70206, #F05B4F, #F4C63D, #453D3F) !default; +$ct-series-names: (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) !default; +$ct-series-colors: ( + #d70206, + #f05b4f, + #f4c63d, + #d17905, + #453d3f, + #59922b, + #0544d3, + #6b0392, + #f05b4f, + #dda458, + #eacf7d, + #86797d, + #b2c326, + #6188e2, + #a748ca +) !default; From 690c77db8022645d96d485cf8e59c0507f65bbef Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 16 Jan 2015 22:31:07 +0100 Subject: [PATCH 148/593] Fixed jshint warinings by adding $ and Chartist to known globals --- test/.jshintrc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/.jshintrc b/test/.jshintrc index b1be025b..b0aa0ed4 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -30,7 +30,9 @@ "inject": false, "it": false, "jasmine": false, - "spyOn": false + "spyOn": false, + "$": false, + "Chartist": false } } From a69e496c341571c2aa9946f3485f32cf27530538 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 17 Jan 2015 03:34:58 +0100 Subject: [PATCH 149/593] Added data event to base chart type, fixes #154 --- src/scripts/base.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index f13c2df1..abe5780c 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -21,12 +21,21 @@ * @memberof Chartist.Base */ function update(data, options) { - this.data = data || this.data; - if (typeof options !== 'undefined') { + if(data) { + this.data = data; + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'update', + data: this.data + }); + } + + if(options) { this.options = Chartist.extend({}, this.options, options); this.optionsProvider.removeMediaQueryListeners(); this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); } + this.createChart(this.optionsProvider.currentOptions); return this; } @@ -115,6 +124,12 @@ this.update(); }.bind(this); + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'initial', + data: this.data + }); + if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { From 87d5ccbfe2b26014773270fdf3e9548da82017e1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 17 Jan 2015 05:33:06 +0100 Subject: [PATCH 150/593] Added helper functions for serializing data to DOM attribute values --- src/scripts/core.js | 69 ++++++++++++++++++++++++++++++++++++++++++ test/spec/spec-core.js | 43 ++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/src/scripts/core.js b/src/scripts/core.js index 127d47b9..d288fc2b 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -58,6 +58,18 @@ var Chartist = { return target; }; + /** + * Replaces all occurrences of subStr in str with newSubStr and returns a new string. + * + * @param {String} str + * @param {String} subStr + * @param {String} newSubStr + * @returns {String} + */ + Chartist.replaceAll = function(str, subStr, newSubStr) { + return str.replace(new RegExp(subStr, 'g'), newSubStr); + }; + /** * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. * @@ -148,6 +160,63 @@ var Chartist = { return result; }; + /** + * A map with characters to escape for strings to be safely used as attribute values. + * + * @type {Object} + */ + Chartist.escapingMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' + }; + + /** + * 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. + * If called with null or undefined the function will return immediately with null or undefined. + * + * @param {Number|String|Object} data + * @returns {String} + */ + Chartist.serialize = function(data) { + if(data === null || data === undefined) { + return data; + } else if(typeof data === 'number') { + data = ''+data; + } else if(typeof data === 'object') { + data = JSON.stringify({data: data}); + } + + return Object.keys(Chartist.escapingMap).reduce(function(result, key) { + return Chartist.replaceAll(result, key, Chartist.escapingMap[key]); + }, data); + }; + + /** + * 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. + * + * @param {String} data + * @returns {String|Number|Object} + */ + Chartist.deserialize = function(data) { + if(typeof data !== 'string') { + return data; + } + + data = Object.keys(Chartist.escapingMap).reduce(function(result, key) { + return Chartist.replaceAll(result, Chartist.escapingMap[key], key); + }, data); + + try { + data = JSON.parse(data); + data = data.data !== undefined ? data.data : data; + } catch(e) {} + + return data; + }; + /** * Create or reinitialize the SVG element for the chart * diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index ffa6147f..41747a3d 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -39,4 +39,47 @@ describe('Chartist core', function() { expect(container).toContainElement('.ct-snake-bar'); }); }); + + describe('serialization tests', function () { + it('should serialize and deserialize regular strings', function() { + var input = 'String test'; + expect(input).toMatch(Chartist.deserialize(Chartist.serialize(input))); + }); + + it('should serialize and deserialize strings with critical characters', function() { + var input = 'String test with critical characters " < > \' & &'; + expect(input).toMatch(Chartist.deserialize(Chartist.serialize(input))); + }); + + it('should serialize and deserialize numbers', function() { + var input = 12345.6789; + expect(input).toMatch(Chartist.deserialize(Chartist.serialize(input))); + }); + + it('should serialize and deserialize dates', function() { + var input = new Date(0); + expect(+input).toMatch(+new Date(Chartist.deserialize(Chartist.serialize(input)))); + }); + + it('should serialize and deserialize complex object types', function() { + var input = { + a: { + b: 100, + c: 'String test', + d: 'String test with critical characters " < > \' & &', + e: { + f: 'String test' + } + } + }; + + expect(input).toMatch(Chartist.deserialize(Chartist.serialize(input))); + }); + + it('should serialize and deserialize null, undefined and NaN', function() { + expect(null).toMatch(Chartist.deserialize(Chartist.serialize(null))); + expect(undefined).toMatch(Chartist.deserialize(Chartist.serialize(undefined))); + expect(NaN).toMatch(Chartist.deserialize(Chartist.serialize('NaN'))); + }); + }); }); From 300dcbebc44ecaa9916d441d1981c8e66b4dc252 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 17 Jan 2015 05:34:18 +0100 Subject: [PATCH 151/593] Fixed object reference issue in getArrayData --- src/scripts/core.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index d288fc2b..eedbc2ba 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -263,13 +263,22 @@ var Chartist = { * @return {Array} A plain array that contains the data to be visualized in the chart */ Chartist.getDataArray = function (data) { - var array = []; + var array = [], + value, + localData; for (var i = 0; i < data.series.length; i++) { // If the series array contains an object with a data property we will use the property - // otherwise the value directly (array or number) - array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? - data.series[i].data : data.series[i]; + // otherwise the value directly (array or number). + // We create a copy of the original data array with Array.prototype.push.apply + localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; + if(localData instanceof Array) { + array[i] = []; + Array.prototype.push.apply(array[i], localData); + } else { + array[i] = localData; + } + // Convert values to number for (var j = 0; j < array[i].length; j++) { From 6cc473964e46ab979579d2dab6a95474af658dc5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 17 Jan 2015 05:35:56 +0100 Subject: [PATCH 152/593] Added possibility to specify meta data in series and values using object notation, fixes #149 --- src/scripts/charts/bar.js | 16 +++++++++------- src/scripts/charts/line.js | 16 +++++++++------- src/scripts/charts/pie.js | 3 ++- src/scripts/core.js | 6 ++++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 71e03249..c291cfce 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -128,12 +128,11 @@ seriesGroups[i] = this.svg.elem('g'); - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) + }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -167,7 +166,10 @@ x2: p.x, y2: y2 }, options.classNames.bar).attr({ - 'value': normalizedData[i][j] + 'value': normalizedData[i][j], + 'meta': this.data.series[i].data ? + Chartist.serialize(this.data.series[i].data[j].meta) : + Chartist.serialize(this.data.series[i][j].meta) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 40b49b7c..55bb9c29 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -115,12 +115,11 @@ for (var i = 0; i < this.data.series.length; i++) { seriesGroups[i] = this.svg.elem('g'); - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) + }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -145,7 +144,10 @@ x2: p.x + 0.01, y2: p.y }, options.classNames.point).attr({ - 'value': normalizedData[i][j] + 'value': normalizedData[i][j], + 'meta': this.data.series[i].data ? + Chartist.serialize(this.data.series[i].data[j].meta) : + Chartist.serialize(this.data.series[i][j].meta) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 60cb3a7c..dbfc757f 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -122,7 +122,8 @@ // If the series is an object and contains a name we add a custom attribute if(this.data.series[i].name) { seriesGroups[i].attr({ - 'series-name': this.data.series[i].name + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) }, Chartist.xmlNs.uri); } diff --git a/src/scripts/core.js b/src/scripts/core.js index eedbc2ba..1b8487e0 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -280,9 +280,11 @@ var Chartist = { } - // Convert values to number + // Convert object values to numbers for (var j = 0; j < array[i].length; j++) { - array[i][j] = +array[i][j]; + value = array[i][j]; + value = value.value || value; + array[i][j] = +value; } } From 9a0c0755cf5b69759cf40572faae6e8a82651b3d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 17 Jan 2015 05:50:59 +0100 Subject: [PATCH 153/593] Updated library to 0.6.0 --- CHANGELOG.md | 9 ++ bower.json | 2 +- dist/chartist.js | 167 +++++++++++++++++---- dist/chartist.min.css | 6 +- dist/chartist.min.js | 6 +- dist/chartist.min.js.map | 2 +- dist/scss/settings/_chartist-settings.scss | 20 ++- package.json | 2 +- src/scripts/core.js | 2 +- 9 files changed, 175 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 557cc679..e2d3fb4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +v0.6.0 - 17 Jan 2015 +-------------------- +- Added 14 default colors for colored series +- Added data event that allows you to transform the data before it gets rendered in Chartist. This is also useful for plugin authors that would like to create plugins which modify data. +- Possibility to specify meta data in the data object passed to Chartist that will be written to custom attributes into the DOM. +- Possibility to specify options when calling chart.update in order to override the current options with new ones +- Fixed some missing entries in the bower ignore section to exclude the documentation site as well as the grunt tasks +- Fixed issue when Chartist is initialized in a container that already contains SVG + v0.5.0 - 14 Dec 2014 -------------------- - Added new option for line and bar chart to use full width of the chart area by skipping the last grid line diff --git a/bower.json b/bower.json index 3be1dcc6..9f855e6b 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.5.0", + "version": "0.6.0", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 8d7b2957..d177eef0 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,8 +14,8 @@ } }(this, function () { - /* Chartist.js 0.5.0 - * Copyright © 2014 Gion Kunz + /* Chartist.js 0.6.0 + * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.5.0' + version: '0.6.0' }; (function (window, document, Chartist) { @@ -79,6 +79,18 @@ return target; }; + /** + * Replaces all occurrences of subStr in str with newSubStr and returns a new string. + * + * @param {String} str + * @param {String} subStr + * @param {String} newSubStr + * @returns {String} + */ + Chartist.replaceAll = function(str, subStr, newSubStr) { + return str.replace(new RegExp(subStr, 'g'), newSubStr); + }; + /** * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. * @@ -169,6 +181,63 @@ return result; }; + /** + * A map with characters to escape for strings to be safely used as attribute values. + * + * @type {Object} + */ + Chartist.escapingMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' + }; + + /** + * 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. + * If called with null or undefined the function will return immediately with null or undefined. + * + * @param {Number|String|Object} data + * @returns {String} + */ + Chartist.serialize = function(data) { + if(data === null || data === undefined) { + return data; + } else if(typeof data === 'number') { + data = ''+data; + } else if(typeof data === 'object') { + data = JSON.stringify({data: data}); + } + + return Object.keys(Chartist.escapingMap).reduce(function(result, key) { + return Chartist.replaceAll(result, key, Chartist.escapingMap[key]); + }, data); + }; + + /** + * 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. + * + * @param {String} data + * @returns {String|Number|Object} + */ + Chartist.deserialize = function(data) { + if(typeof data !== 'string') { + return data; + } + + data = Object.keys(Chartist.escapingMap).reduce(function(result, key) { + return Chartist.replaceAll(result, Chartist.escapingMap[key], key); + }, data); + + try { + data = JSON.parse(data); + data = data.data !== undefined ? data.data : data; + } catch(e) {} + + return data; + }; + /** * Create or reinitialize the SVG element for the chart * @@ -185,10 +254,13 @@ width = width || '100%'; height = height || '100%'; - svg = container.querySelector('svg'); - if(svg) { + // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it + // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ + Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { + return svg.getAttribute(Chartist.xmlNs.qualifiedName); + }).forEach(function removePreviousElement(svg) { container.removeChild(svg); - } + }); // Create svg object with width and height or use 100% as default svg = new Chartist.Svg('svg').attr({ @@ -212,17 +284,28 @@ * @return {Array} A plain array that contains the data to be visualized in the chart */ Chartist.getDataArray = function (data) { - var array = []; + var array = [], + value, + localData; for (var i = 0; i < data.series.length; i++) { // If the series array contains an object with a data property we will use the property - // otherwise the value directly (array or number) - array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? - data.series[i].data : data.series[i]; + // otherwise the value directly (array or number). + // We create a copy of the original data array with Array.prototype.push.apply + localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; + if(localData instanceof Array) { + array[i] = []; + Array.prototype.push.apply(array[i], localData); + } else { + array[i] = localData; + } + - // Convert values to number + // Convert object values to numbers for (var j = 0; j < array[i].length; j++) { - array[i][j] = +array[i][j]; + value = array[i][j]; + value = value.value || value; + array[i][j] = +value; } } @@ -1078,10 +1161,25 @@ * Updates the chart which currently does a full reconstruction of the SVG DOM * * @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. + * @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. * @memberof Chartist.Base */ - function update(data) { - this.data = data || this.data; + function update(data, options) { + if(data) { + this.data = data; + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'update', + data: this.data + }); + } + + if(options) { + this.options = Chartist.extend({}, this.options, options); + this.optionsProvider.removeMediaQueryListeners(); + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + } + this.createChart(this.optionsProvider.currentOptions); return this; } @@ -1170,6 +1268,12 @@ this.update(); }.bind(this); + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'initial', + data: this.data + }); + if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { @@ -1920,12 +2024,11 @@ for (var i = 0; i < this.data.series.length; i++) { seriesGroups[i] = this.svg.elem('g'); - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) + }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -1950,7 +2053,10 @@ x2: p.x + 0.01, y2: p.y }, options.classNames.point).attr({ - 'value': normalizedData[i][j] + 'value': normalizedData[i][j], + 'meta': this.data.series[i].data ? + Chartist.serialize(this.data.series[i].data[j].meta) : + Chartist.serialize(this.data.series[i][j].meta) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { @@ -2252,12 +2358,11 @@ seriesGroups[i] = this.svg.elem('g'); - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name - }, Chartist.xmlNs.uri); - } + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) + }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -2291,7 +2396,10 @@ x2: p.x, y2: y2 }, options.classNames.bar).attr({ - 'value': normalizedData[i][j] + 'value': normalizedData[i][j], + 'meta': this.data.series[i].data ? + Chartist.serialize(this.data.series[i].data[j].meta) : + Chartist.serialize(this.data.series[i][j].meta) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { @@ -2492,7 +2600,8 @@ // If the series is an object and contains a name we add a custom attribute if(this.data.series[i].name) { seriesGroups[i].attr({ - 'series-name': this.data.series[i].name + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) }, Chartist.xmlNs.uri); } diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 32aff3f4..63a91f5e 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,7 +1,7 @@ -/* Chartist.js 0.5.0 - * Copyright © 2014 Gion Kunz +/* Chartist.js 0.6.0 + * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -.ct-chart .ct-label,.ct-chart .ct-label.ct-horizontal{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:left}.ct-chart .ct-label.ct-vertical{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:right}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#F05B4F}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#F05B4F}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#F4C63D}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#F4C63D}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#453D3F}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#453D3F}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file +.ct-chart .ct-label,.ct-chart .ct-label.ct-horizontal{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:left}.ct-chart .ct-label.ct-vertical{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:right}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#f4c63d}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#f4c63d}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#d17905}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#d17905}.ct-chart .ct-series.ct-series-e .ct-bar,.ct-chart .ct-series.ct-series-e .ct-line,.ct-chart .ct-series.ct-series-e .ct-point,.ct-chart .ct-series.ct-series-e .ct-slice.ct-donut{stroke:#453d3f}.ct-chart .ct-series.ct-series-e .ct-area,.ct-chart .ct-series.ct-series-e .ct-slice:not(.ct-donut){fill:#453d3f}.ct-chart .ct-series.ct-series-f .ct-bar,.ct-chart .ct-series.ct-series-f .ct-line,.ct-chart .ct-series.ct-series-f .ct-point,.ct-chart .ct-series.ct-series-f .ct-slice.ct-donut{stroke:#59922b}.ct-chart .ct-series.ct-series-f .ct-area,.ct-chart .ct-series.ct-series-f .ct-slice:not(.ct-donut){fill:#59922b}.ct-chart .ct-series.ct-series-g .ct-bar,.ct-chart .ct-series.ct-series-g .ct-line,.ct-chart .ct-series.ct-series-g .ct-point,.ct-chart .ct-series.ct-series-g .ct-slice.ct-donut{stroke:#0544d3}.ct-chart .ct-series.ct-series-g .ct-area,.ct-chart .ct-series.ct-series-g .ct-slice:not(.ct-donut){fill:#0544d3}.ct-chart .ct-series.ct-series-h .ct-bar,.ct-chart .ct-series.ct-series-h .ct-line,.ct-chart .ct-series.ct-series-h .ct-point,.ct-chart .ct-series.ct-series-h .ct-slice.ct-donut{stroke:#6b0392}.ct-chart .ct-series.ct-series-h .ct-area,.ct-chart .ct-series.ct-series-h .ct-slice:not(.ct-donut){fill:#6b0392}.ct-chart .ct-series.ct-series-i .ct-bar,.ct-chart .ct-series.ct-series-i .ct-line,.ct-chart .ct-series.ct-series-i .ct-point,.ct-chart .ct-series.ct-series-i .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-i .ct-area,.ct-chart .ct-series.ct-series-i .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-j .ct-bar,.ct-chart .ct-series.ct-series-j .ct-line,.ct-chart .ct-series.ct-series-j .ct-point,.ct-chart .ct-series.ct-series-j .ct-slice.ct-donut{stroke:#dda458}.ct-chart .ct-series.ct-series-j .ct-area,.ct-chart .ct-series.ct-series-j .ct-slice:not(.ct-donut){fill:#dda458}.ct-chart .ct-series.ct-series-k .ct-bar,.ct-chart .ct-series.ct-series-k .ct-line,.ct-chart .ct-series.ct-series-k .ct-point,.ct-chart .ct-series.ct-series-k .ct-slice.ct-donut{stroke:#eacf7d}.ct-chart .ct-series.ct-series-k .ct-area,.ct-chart .ct-series.ct-series-k .ct-slice:not(.ct-donut){fill:#eacf7d}.ct-chart .ct-series.ct-series-l .ct-bar,.ct-chart .ct-series.ct-series-l .ct-line,.ct-chart .ct-series.ct-series-l .ct-point,.ct-chart .ct-series.ct-series-l .ct-slice.ct-donut{stroke:#86797d}.ct-chart .ct-series.ct-series-l .ct-area,.ct-chart .ct-series.ct-series-l .ct-slice:not(.ct-donut){fill:#86797d}.ct-chart .ct-series.ct-series-m .ct-bar,.ct-chart .ct-series.ct-series-m .ct-line,.ct-chart .ct-series.ct-series-m .ct-point,.ct-chart .ct-series.ct-series-m .ct-slice.ct-donut{stroke:#b2c326}.ct-chart .ct-series.ct-series-m .ct-area,.ct-chart .ct-series.ct-series-m .ct-slice:not(.ct-donut){fill:#b2c326}.ct-chart .ct-series.ct-series-n .ct-bar,.ct-chart .ct-series.ct-series-n .ct-line,.ct-chart .ct-series.ct-series-n .ct-point,.ct-chart .ct-series.ct-series-n .ct-slice.ct-donut{stroke:#6188e2}.ct-chart .ct-series.ct-series-n .ct-area,.ct-chart .ct-series.ct-series-n .ct-slice:not(.ct-donut){fill:#6188e2}.ct-chart .ct-series.ct-series-o .ct-bar,.ct-chart .ct-series.ct-series-o .ct-line,.ct-chart .ct-series.ct-series-o .ct-point,.ct-chart .ct-series.ct-series-o .ct-slice.ct-donut{stroke:#a748ca}.ct-chart .ct-series.ct-series-o .ct-area,.ct-chart .ct-series.ct-series-o .ct-slice:not(.ct-donut){fill:#a748ca}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 5506fa14..8761d308 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.5.0 - * Copyright © 2014 Gion Kunz +/* Chartist.js 0.6.0 + * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.5.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",f=a.querySelector("svg"),f&&a.removeChild(f),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.getDataArray=function(a){for(var b=[],c=0;cd;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.6.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.getDataArray=function(a){for(var b,c,d=[],e=0;ed;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index c60ad109..5f63faeb 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","stripUnit","value","replace","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","createSvg","container","width","height","className","svg","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","data","array","i","series","undefined","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":20439,"pos":20434,"col":16,"line":552,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":20439,"pos":20434,"col":16,"line":552,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","Object","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","initializeTimeoutId","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","xmlNs","qualifiedName","uri","firstChild","insertBefore","ns","getAttributeNS","getAttribute","keys","key","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","querySelectorAll","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","filter","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","stackBars","serialSums","reduce","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.5.0\n * Copyright © 2014 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.5.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\n }\n }\n });\n\n return target;\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * 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 svg = container.querySelector('svg');\n if(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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [];\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number)\n array[i] = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ?\n data.series[i].data : data.series[i];\n\n // Convert values to number\n for (var j = 0; j < array[i].length; j++) {\n array[i][j] = +array[i][j];\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update(data) {\n this.data = data || this.data;\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","localData","array","i","series","push","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","initializeTimeoutId","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","meta","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","stackBars","serialSums","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.6.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.6.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @returns {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * A map with characters to escape for strings to be safely used as attribute values.\n *\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 * @param {Number|String|Object} data\n * @returns {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 * @param {String} data\n * @returns {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.getAttribute(Chartist.xmlNs.qualifiedName);\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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [],\n value,\n localData;\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value || value;\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update(data, options) {\n if(data) {\n this.data = data;\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({}, this.options, options);\n this.optionsProvider.removeMediaQueryListeners();\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n }\n\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 // 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 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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/dist/scss/settings/_chartist-settings.scss b/dist/scss/settings/_chartist-settings.scss index 059e3d8a..b244b592 100644 --- a/dist/scss/settings/_chartist-settings.scss +++ b/dist/scss/settings/_chartist-settings.scss @@ -61,5 +61,21 @@ $ct-include-colored-series: $ct-include-classes !default; $ct-include-alternative-responsive-containers: $ct-include-classes !default; // Series names and colors. This can be extended or customized as desired. Just add more series and colors. -$ct-series-names: (a, b, c, d) !default; -$ct-series-colors: (#d70206, #F05B4F, #F4C63D, #453D3F) !default; +$ct-series-names: (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) !default; +$ct-series-colors: ( + #d70206, + #f05b4f, + #f4c63d, + #d17905, + #453d3f, + #59922b, + #0544d3, + #6b0392, + #f05b4f, + #dda458, + #eacf7d, + #86797d, + #b2c326, + #6188e2, + #a748ca +) !default; diff --git a/package.json b/package.json index 6ae6a70d..b031e42c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.5.0", + "version": "0.6.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index 1b8487e0..01a463d8 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.5.0' + version: '0.6.0' }; (function (window, document, Chartist) { From 1f658791e7b656a05da7d709f68e2899e3c7d90a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 17 Jan 2015 06:01:56 +0100 Subject: [PATCH 154/593] Reversed drawing order as outlined in #113 --- src/scripts/charts/line.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 55bb9c29..8ab55b8d 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -180,6 +180,22 @@ } } + if(options.showLine) { + var line = seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: line + }); + } + if(options.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. @@ -210,22 +226,6 @@ element: area }); } - - if(options.showLine) { - var line = seriesGroups[i].elem('path', { - d: pathElements.join('') - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[i], - index: i, - group: seriesGroups[i], - element: line - }); - } } } From 641a229d9518d5242cf95018c33d09b981b67f31 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 17 Jan 2015 06:05:51 +0100 Subject: [PATCH 155/593] Fixes for drawing order --- dist/chartist.js | 32 ++++++++++++++++---------------- dist/chartist.min.js | 2 +- dist/chartist.min.js.map | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dist/chartist.js b/dist/chartist.js index d177eef0..486bca4c 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -2089,6 +2089,22 @@ } } + if(options.showLine) { + var line = seriesGroups[i].elem('path', { + d: pathElements.join('') + }, options.classNames.line, true).attr({ + 'values': normalizedData[i] + }, Chartist.xmlNs.uri); + + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[i], + index: i, + group: seriesGroups[i], + element: line + }); + } + if(options.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. @@ -2119,22 +2135,6 @@ element: area }); } - - if(options.showLine) { - var line = seriesGroups[i].elem('path', { - d: pathElements.join('') - }, options.classNames.line, true).attr({ - 'values': normalizedData[i] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[i], - index: i, - group: seriesGroups[i], - element: line - }); - } } } diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 8761d308..8cf5c94f 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -4,5 +4,5 @@ * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.6.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.getDataArray=function(a){for(var b,c,d=[],e=0;ed;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.6.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.getDataArray=function(a){for(var b,c,d=[],e=0;ed;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 5f63faeb..e1228b72 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","localData","array","i","series","push","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","initializeTimeoutId","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","meta","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","areaBase","areaPathElements","areaBaseProjected","area","line","Line","defaultOptions","stackBars","serialSums","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.6.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.6.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @returns {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * A map with characters to escape for strings to be safely used as attribute values.\n *\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 * @param {Number|String|Object} data\n * @returns {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 * @param {String} data\n * @returns {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.getAttribute(Chartist.xmlNs.qualifiedName);\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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [],\n value,\n localData;\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value || value;\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update(data, options) {\n if(data) {\n this.data = data;\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({}, this.options, options);\n this.optionsProvider.removeMediaQueryListeners();\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n }\n\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 // 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 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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","localData","array","i","series","push","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","initializeTimeoutId","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","meta","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","line","areaBase","areaPathElements","areaBaseProjected","area","Line","defaultOptions","stackBars","serialSums","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.6.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.6.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @returns {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * A map with characters to escape for strings to be safely used as attribute values.\n *\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 * @param {Number|String|Object} data\n * @returns {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 * @param {String} data\n * @returns {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.getAttribute(Chartist.xmlNs.qualifiedName);\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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [],\n value,\n localData;\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value || value;\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update(data, options) {\n if(data) {\n this.data = data;\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({}, this.options, options);\n this.optionsProvider.removeMediaQueryListeners();\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n }\n\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 // 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 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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file From 5ac2e9b4955ed3d257b8ba85976814ca472cf5e7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 18 Jan 2015 19:16:24 +0100 Subject: [PATCH 156/593] Fixed dox comments --- src/scripts/core.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scripts/core.js b/src/scripts/core.js index 01a463d8..8655ccf7 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -61,6 +61,7 @@ var Chartist = { /** * Replaces all occurrences of subStr in str with newSubStr and returns a new string. * + * @memberof Chartist.Core * @param {String} str * @param {String} subStr * @param {String} newSubStr @@ -163,6 +164,7 @@ var Chartist = { /** * A map with characters to escape for strings to be safely used as attribute values. * + * @memberof Chartist.Core * @type {Object} */ Chartist.escapingMap = { @@ -177,6 +179,7 @@ var Chartist = { * 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. * If called with null or undefined the function will return immediately with null or undefined. * + * @memberof Chartist.Core * @param {Number|String|Object} data * @returns {String} */ @@ -197,6 +200,7 @@ var Chartist = { /** * 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. * + * @memberof Chartist.Core * @param {String} data * @returns {String|Number|Object} */ From e362ee2046d3d23b2b1bcab8093739c728fa9cea Mon Sep 17 00:00:00 2001 From: Daniel Diekmeier Date: Mon, 19 Jan 2015 11:10:59 +0100 Subject: [PATCH 157/593] Added parameter for smoothing --- src/scripts/core.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 7b37c5a1..ba44637e 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -722,8 +722,9 @@ var Chartist = { return delta; }; - //http://schepers.cc/getting-to-the-point - Chartist.catmullRom2bezier = function (crp, z) { + // http://schepers.cc/getting-to-the-point + // https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline + Chartist.catmullRom2bezier = function (crp, c, z) { var d = []; for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { var p = [ @@ -748,12 +749,13 @@ var Chartist = { p[0] = {x: +crp[i], y: +crp[i + 1]}; } } + var t = (1 - c); d.push( [ - (-p[0].x + 6 * p[1].x + p[2].x) / 6, - (-p[0].y + 6 * p[1].y + p[2].y) / 6, - (p[1].x + 6 * p[2].x - p[3].x) / 6, - (p[1].y + 6 * p[2].y - p[3].y) / 6, + (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), + (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), + (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), + (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), p[2].x, p[2].y ] From 3152087a58a81864a2ae466b0b63f89d0a8f2a7a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 23 Jan 2015 00:09:09 +0100 Subject: [PATCH 158/593] Moving initial data event from constructor to init function, fixes #159 --- src/scripts/base.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index abe5780c..69d1e486 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -95,6 +95,12 @@ }.bind(this)); } + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'initial', + data: this.data + }); + // Create the first chart this.createChart(this.optionsProvider.currentOptions); @@ -124,12 +130,6 @@ this.update(); }.bind(this); - // Event for data transformation that allows to manipulate the data before it gets rendered in the charts - this.eventEmitter.emit('data', { - type: 'initial', - data: this.data - }); - if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { From 436f5089dffd436a7f068d8e4b2344d9953cccc3 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 23 Jan 2015 00:10:28 +0100 Subject: [PATCH 159/593] Taking initialization timeout into consideration when updating the chart, fixes #160 --- src/scripts/base.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index 69d1e486..b3d1909f 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -18,9 +18,10 @@ * * @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. * @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. + * @param {Boolean} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already. * @memberof Chartist.Base */ - function update(data, options) { + function update(data, options, extendObjects) { if(data) { this.data = data; // Event for data transformation that allows to manipulate the data before it gets rendered in the charts @@ -31,12 +32,21 @@ } if(options) { - this.options = Chartist.extend({}, this.options, options); - this.optionsProvider.removeMediaQueryListeners(); - this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + this.options = Chartist.extend({}, extendObjects ? this.options : {}, options); + + // If chartist was not initialized yet, we just set the options and leave the rest to the initialization + if(!this.initializeTimeoutId) { + this.optionsProvider.removeMediaQueryListeners(); + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + } } - this.createChart(this.optionsProvider.currentOptions); + // Only re-created the chart if it has been initialized yet + if(!this.initializeTimeoutId) { + this.createChart(this.optionsProvider.currentOptions); + } + + // Return a reference to the chart object to chain up calls return this; } From 0215ce644559b239a88ac78242b4f28c0f1097f0 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 23 Jan 2015 00:11:40 +0100 Subject: [PATCH 160/593] Added more tests to cover some base chart functionality --- tasks/jasmine.js | 3 ++ test/spec/spec-base-chart.js | 65 ++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 test/spec/spec-base-chart.js diff --git a/tasks/jasmine.js b/tasks/jasmine.js index 6f33c8d6..a7ea3e4a 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -29,6 +29,9 @@ module.exports = function (grunt) { 'http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', 'node_modules/jasmine-jquery/lib/jasmine-jquery.js' ], + styles: [ + '.tmp/styles/main.css' + ], phantomjs: { 'ignore-ssl-errors': true } diff --git a/test/spec/spec-base-chart.js b/test/spec/spec-base-chart.js new file mode 100644 index 00000000..a8f01345 --- /dev/null +++ b/test/spec/spec-base-chart.js @@ -0,0 +1,65 @@ +describe('Base chart tests', function() { + 'use strict'; + + beforeEach(function() { + + }); + + afterEach(function() { + + }); + + it('should fire initial data event correctly', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }); + + chart.on('data', function(data) { + expect(data.type).toEqual('initial'); + expect(data.data.series[0]).toEqual([0, 1, 2, 3]); + done(); + }); + }); + + it('should fire update data event correctly', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }); + + chart.on('data', function(data) { + if(data.type === 'update') { + expect(data.data.series[0]).toEqual([3, 2, 1, 0]); + done(); + } + }); + + chart.update({ + labels: [1, 2, 3, 4], + series: [[3, 2, 1, 0]] + }); + }); + + it('should transform data before rendering with data event', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }); + + chart.on('data', function(data) { + data.data.series[0] = data.data.series[0].reverse(); + }); + + chart.on('created', function() { + expect(chart.data.series[0]).toEqual([3, 2, 1, 0]); + done(); + }); + }); +}); From 6891c5644d4b4aa8818dca88897829734e306702 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 23 Jan 2015 00:15:08 +0100 Subject: [PATCH 161/593] Version bump to 0.6.1 --- CHANGELOG.md | 5 +++++ bower.json | 2 +- dist/chartist.js | 40 +++++++++++++++++++++++++++------------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 ++-- dist/chartist.min.js.map | 2 +- package.json | 2 +- src/scripts/core.js | 2 +- 8 files changed, 39 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2d3fb4d..dcb54269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v0.6.1 - 23 Jan 2015 +-------------------- +- Fixed bug that prevented data events to be captured +- Fixed bug with update function called in the same call stack as chart constructor + v0.6.0 - 17 Jan 2015 -------------------- - Added 14 default colors for colored series diff --git a/bower.json b/bower.json index 9f855e6b..8749ce3a 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.6.0", + "version": "0.6.1", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 486bca4c..f452a56c 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { - /* Chartist.js 0.6.0 + /* Chartist.js 0.6.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.6.0' + version: '0.6.1' }; (function (window, document, Chartist) { @@ -82,6 +82,7 @@ /** * Replaces all occurrences of subStr in str with newSubStr and returns a new string. * + * @memberof Chartist.Core * @param {String} str * @param {String} subStr * @param {String} newSubStr @@ -184,6 +185,7 @@ /** * A map with characters to escape for strings to be safely used as attribute values. * + * @memberof Chartist.Core * @type {Object} */ Chartist.escapingMap = { @@ -198,6 +200,7 @@ * 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. * If called with null or undefined the function will return immediately with null or undefined. * + * @memberof Chartist.Core * @param {Number|String|Object} data * @returns {String} */ @@ -218,6 +221,7 @@ /** * 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. * + * @memberof Chartist.Core * @param {String} data * @returns {String|Number|Object} */ @@ -1162,9 +1166,10 @@ * * @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. * @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. + * @param {Boolean} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already. * @memberof Chartist.Base */ - function update(data, options) { + function update(data, options, extendObjects) { if(data) { this.data = data; // Event for data transformation that allows to manipulate the data before it gets rendered in the charts @@ -1175,12 +1180,21 @@ } if(options) { - this.options = Chartist.extend({}, this.options, options); - this.optionsProvider.removeMediaQueryListeners(); - this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + this.options = Chartist.extend({}, extendObjects ? this.options : {}, options); + + // If chartist was not initialized yet, we just set the options and leave the rest to the initialization + if(!this.initializeTimeoutId) { + this.optionsProvider.removeMediaQueryListeners(); + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + } } - this.createChart(this.optionsProvider.currentOptions); + // Only re-created the chart if it has been initialized yet + if(!this.initializeTimeoutId) { + this.createChart(this.optionsProvider.currentOptions); + } + + // Return a reference to the chart object to chain up calls return this; } @@ -1239,6 +1253,12 @@ }.bind(this)); } + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'initial', + data: this.data + }); + // Create the first chart this.createChart(this.optionsProvider.currentOptions); @@ -1268,12 +1288,6 @@ this.update(); }.bind(this); - // Event for data transformation that allows to manipulate the data before it gets rendered in the charts - this.eventEmitter.emit('data', { - type: 'initial', - data: this.data - }); - if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 63a91f5e..3336c799 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.6.0 +/* Chartist.js 0.6.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 8cf5c94f..b4e8e40c 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.6.0 +/* Chartist.js 0.6.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.6.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.getDataArray=function(a){for(var b,c,d=[],e=0;ed;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.6.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.getDataArray=function(a){for(var b,c,d=[],e=0;ed;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index e1228b72..2752ad06 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","localData","array","i","series","push","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23716,"pos":23711,"col":16,"line":635,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","initializeTimeoutId","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","meta","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","line","areaBase","areaPathElements","areaBaseProjected","area","Line","defaultOptions","stackBars","serialSums","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.6.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.6.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @returns {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * A map with characters to escape for strings to be safely used as attribute values.\n *\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 * @param {Number|String|Object} data\n * @returns {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 * @param {String} data\n * @returns {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.getAttribute(Chartist.xmlNs.qualifiedName);\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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [],\n value,\n localData;\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value || value;\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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 * @memberof Chartist.Base\n */\n function update(data, options) {\n if(data) {\n this.data = data;\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({}, this.options, options);\n this.optionsProvider.removeMediaQueryListeners();\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n }\n\n this.createChart(this.optionsProvider.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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 // Create the first chart\n this.createChart(this.optionsProvider.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 // 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 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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","localData","array","i","series","push","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23840,"pos":23835,"col":16,"line":639,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23840,"pos":23835,"col":16,"line":639,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","meta","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","line","areaBase","areaPathElements","areaBaseProjected","area","Line","defaultOptions","stackBars","serialSums","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.6.1\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.6.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 * @returns {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * 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 * @returns {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 * @returns {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.getAttribute(Chartist.xmlNs.qualifiedName);\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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [],\n value,\n localData;\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value || value;\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index b031e42c..a03c4f46 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.6.0", + "version": "0.6.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index 8655ccf7..7b8489b8 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.6.0' + version: '0.6.1' }; (function (window, document, Chartist) { From a735f43270851c1fa844cfb9a9c2736c444eadd5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 27 Jan 2015 22:14:29 +0100 Subject: [PATCH 162/593] Refactoring of axis creation, fixes #165 --- site/layouts/default.hbs | 3 + src/scripts/axes/axis.js | 39 ++++ src/scripts/axes/linear-scale-axis.js | 31 +++ src/scripts/axes/step-axis.js | 31 +++ src/scripts/charts/bar.js | 128 ++++++++---- src/scripts/charts/line.js | 143 +++++++++---- src/scripts/core.js | 284 +++++++------------------- tasks/jasmine.js | 3 + 8 files changed, 376 insertions(+), 286 deletions(-) create mode 100644 src/scripts/axes/axis.js create mode 100644 src/scripts/axes/linear-scale-axis.js create mode 100644 src/scripts/axes/step-axis.js diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index cf03565d..13568037 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -56,6 +56,9 @@ + + + diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js new file mode 100644 index 00000000..e3e8439c --- /dev/null +++ b/src/scripts/axes/axis.js @@ -0,0 +1,39 @@ +/** + * Axis base class used to implement different axis types + * + * @module Chartist.Axis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + var axisUnits = { + x: { + pos: 'x', + len: 'width', + dir: 'horizontal' + }, + y: { + pos: 'y', + len: 'height', + dir: 'vertical' + } + }; + + function Axis(units, axisLength, options) { + this.units = units; + this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; + this.axisLength = axisLength; + this.options = options; + } + + Chartist.Axis = Chartist.Class.extend({ + constructor: Axis, + projectValue: function(value, index, data) { + throw new Error('Base axis can\'t be instantiated!'); + } + }); + + Chartist.Axis.units = axisUnits; + +}(window, document, Chartist)); diff --git a/src/scripts/axes/linear-scale-axis.js b/src/scripts/axes/linear-scale-axis.js new file mode 100644 index 00000000..e2912270 --- /dev/null +++ b/src/scripts/axes/linear-scale-axis.js @@ -0,0 +1,31 @@ +/** + * Step axis for step based charts like bar chart or step based line chart + * + * @module Chartist.StepAxis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + function LinearScaleAxis(axisUnit, axisLength, options) { + Chartist.LinearScaleAxis.super.constructor.call(this, + axisUnit, + axisLength, + options); + + this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); + } + + function projectValue(value) { + return { + pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step), + len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) + }; + } + + Chartist.LinearScaleAxis = Chartist.Axis.extend({ + constructor: LinearScaleAxis, + projectValue: projectValue + }); + +}(window, document, Chartist)); diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js new file mode 100644 index 00000000..df6a2064 --- /dev/null +++ b/src/scripts/axes/step-axis.js @@ -0,0 +1,31 @@ +/** + * Step axis for step based charts like bar chart or step based line chart + * + * @module Chartist.StepAxis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + function StepAxis(axisUnit, axisLength, options) { + Chartist.StepAxis.super.constructor.call(this, + axisUnit, + axisLength, + options); + + this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); + } + + function projectValue(value, index) { + return { + pos: this.stepLength * index, + len: this.stepLength + }; + } + + Chartist.StepAxis = Chartist.Axis.extend({ + constructor: StepAxis, + projectValue: projectValue + }); + +}(window, document, Chartist)); diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index c291cfce..e82fe4b9 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -85,7 +85,7 @@ */ function createChart(options) { var seriesGroups = [], - bounds, + projectedValues, normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length), highLow; @@ -102,46 +102,102 @@ } else { highLow = Chartist.getHighLow(normalizedData); } - - // initialize bounds - bounds = Chartist.getBounds(this.svg, highLow, options, 0); + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); var chartRect = Chartist.createChartRect(this.svg, options); + + var axisX = new Chartist.StepAxis( + Chartist.Axis.units.x, + chartRect.x2 - chartRect.x1, { + stepCount: this.data.labels.length, + stretch: options.fullWidth + } + ); + + var axisY = new Chartist.LinearScaleAxis( + Chartist.Axis.units.y, + chartRect.y1 - chartRect.y2, { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace, + referenceValue: 0 + } + ); + // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup), + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), + gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup), // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options), + zeroPoint = chartRect.y1 - axisY.projectValue(0).pos, // Used to track the screen coordinates of stacked bars stackedBarValues = []; - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.drawAxis( + axisX, + this.data.labels, + function(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + chartRect, + gridGroup, + chartRect.y2, + labelGroup, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + Chartist.drawAxis( + axisY, + axisY.bounds.values, + function(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + chartRect, + gridGroup, + chartRect.x1, + labelGroup, { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) + }, + this.supportsForeignObject, + options, + this.eventEmitter + ); // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { + this.data.series.forEach(function(series, seriesIndex) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = i - (this.data.series.length - 1) / 2, + var biPol = seriesIndex - (this.data.series.length - 1) / 2, // Half of the period width between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2; + periodHalfWidth = chartRect.width() / (normalizedData[seriesIndex].length - (options.fullWidth ? 1 : 0)) / 2; - seriesGroups[i] = this.svg.elem('g'); + seriesGroups[seriesIndex] = this.svg.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) + seriesGroups[seriesIndex].attr({ + 'series-name': series.name, + 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ + seriesGroups[seriesIndex].addClass([ options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options), + normalizedData[seriesIndex].forEach(function(value, valueIndex) { + var p = { + x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + }, bar, previousStack, y1, @@ -153,41 +209,41 @@ p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance; // Enter value in stacked bar values used to remember previous screen value for stacking up bars - previousStack = stackedBarValues[j] || zeroPoint.y; - stackedBarValues[j] = previousStack - (zeroPoint.y - p.y); + previousStack = stackedBarValues[valueIndex] || zeroPoint; + stackedBarValues[valueIndex] = previousStack - (zeroPoint - p.y); // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - y1 = options.stackBars ? previousStack : zeroPoint.y; - y2 = options.stackBars ? stackedBarValues[j] : p.y; + y1 = options.stackBars ? previousStack : zeroPoint; + y2 = options.stackBars ? stackedBarValues[valueIndex] : p.y; - bar = seriesGroups[i].elem('line', { + bar = seriesGroups[seriesIndex].elem('line', { x1: p.x, y1: y1, x2: p.x, y2: y2 }, options.classNames.bar).attr({ - 'value': normalizedData[i][j], - 'meta': this.data.series[i].data ? - Chartist.serialize(this.data.series[i].data[j].meta) : - Chartist.serialize(this.data.series[i][j].meta) + 'value': value, + 'meta': series.data ? + Chartist.serialize(series.data[valueIndex].meta) : + Chartist.serialize(series[valueIndex].meta) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'bar', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], + value: value, + index: valueIndex, + group: seriesGroups[seriesIndex], element: bar, x1: p.x, y1: y1, x2: p.x, y2: y2 }); - } - } + }.bind(this)); + }.bind(this)); this.eventEmitter.emit('created', { - bounds: bounds, + bounds: axisY.bounds, chartRect: chartRect, svg: this.svg, options: options diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 8ab55b8d..35494e84 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -93,74 +93,131 @@ */ function createChart(options) { var seriesGroups = [], - bounds, normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - // initialize bounds - bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options); - var chartRect = Chartist.createChartRect(this.svg, options); + + var highLow = Chartist.getHighLow(normalizedData); + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); + + var axisX = new Chartist.StepAxis( + Chartist.Axis.units.x, + chartRect.x2 - chartRect.x1, { + stepCount: this.data.labels.length, + stretch: options.fullWidth + } + ); + + var axisY = new Chartist.LinearScaleAxis( + Chartist.Axis.units.y, + chartRect.y1 - chartRect.y2, { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace + } + ); + // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), + gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.drawAxis( + axisX, + this.data.labels, + function(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + chartRect, + gridGroup, + chartRect.y2, + labelGroup, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + Chartist.drawAxis( + axisY, + axisY.bounds.values, + function(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + chartRect, + gridGroup, + chartRect.x1, + labelGroup, + { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) + }, + this.supportsForeignObject, + options, + this.eventEmitter + ); // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - seriesGroups[i] = this.svg.elem('g'); + this.data.series.forEach(function(series, seriesIndex) { + seriesGroups[seriesIndex] = this.svg.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) + seriesGroups[seriesIndex].attr({ + 'series-name': series.name, + 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ + seriesGroups[seriesIndex].addClass([ options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); var p, pathCoordinates = [], point; - for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options); + normalizedData[seriesIndex].forEach(function(value, valueIndex) { + p = { + x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + }; pathCoordinates.push(p.x, p.y); //If we should show points we need to create them now to avoid secondary loop // Small offset for Firefox to render squares correctly if (options.showPoint) { - point = seriesGroups[i].elem('line', { + point = seriesGroups[seriesIndex].elem('line', { x1: p.x, y1: p.y, x2: p.x + 0.01, y2: p.y }, options.classNames.point).attr({ - 'value': normalizedData[i][j], - 'meta': this.data.series[i].data ? - Chartist.serialize(this.data.series[i].data[j].meta) : - Chartist.serialize(this.data.series[i][j].meta) + 'value': value, + 'meta': series.data ? + Chartist.serialize(series.data[valueIndex].meta) : + Chartist.serialize(series[valueIndex].meta) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'point', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], + value: value, + index: valueIndex, + group: seriesGroups[seriesIndex], element: point, x: p.x, y: p.y }); } - } + }.bind(this)); // TODO: Nicer handling of conditions, maybe composition? if (options.showLine || options.showArea) { @@ -181,17 +238,17 @@ } if(options.showLine) { - var line = seriesGroups[i].elem('path', { + var line = seriesGroups[seriesIndex].elem('path', { d: pathElements.join('') }, options.classNames.line, true).attr({ - 'values': normalizedData[i] + 'values': normalizedData[seriesIndex] }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'line', - values: normalizedData[i], - index: i, - group: seriesGroups[i], + values: normalizedData[seriesIndex], + index: seriesIndex, + group: seriesGroups[seriesIndex], element: line }); } @@ -199,38 +256,38 @@ if(options.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); + var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); // If we need to draw area shapes we just make a copy of our pathElements SVG path array var areaPathElements = pathElements.slice(); // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options); + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; // And splice our new area path array to add the missing path elements to close the area shape - areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); + areaPathElements.splice(0, 0, 'M' + chartRect.x1 + ',' + areaBaseProjected); areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; - areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected); // Create the new path for the area shape with the area class from the options - var area = seriesGroups[i].elem('path', { + var area = seriesGroups[seriesIndex].elem('path', { d: areaPathElements.join('') }, options.classNames.area, true).attr({ - 'values': normalizedData[i] + 'values': normalizedData[seriesIndex] }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'area', - values: normalizedData[i], - index: i, - group: seriesGroups[i], + values: normalizedData[seriesIndex], + index: seriesIndex, + group: seriesGroups[seriesIndex], element: area }); } } - } + }.bind(this)); this.eventEmitter.emit('created', { - bounds: bounds, + bounds: axisY.bounds, chartRect: chartRect, svg: this.svg, options: options diff --git a/src/scripts/core.js b/src/scripts/core.js index 7b8489b8..f5ce0d59 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -332,15 +332,13 @@ var Chartist = { * Project a data length into screen coordinates (pixels) * * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart + * @param {Object} axisLength The svg element for the chart * @param {Number} length Single data value from a series array * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} options The Object that contains all the optional values for the chart * @return {Number} The projected data length in pixels */ - Chartist.projectLength = function (svg, length, bounds, options) { - var availableHeight = Chartist.getAvailableHeight(svg, options); - return (length / bounds.range * availableHeight); + Chartist.projectLength = function (axisLength, length, bounds) { + return length / bounds.range * axisLength; }; /** @@ -389,13 +387,13 @@ var Chartist = { * Calculate and retrieve all the bounds for the chart and return them in one array * * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart + * @param {Number} axisLength The length of the Axis used for * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. - * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} scaleMinSpace The minimum projected length a step should result in * @param {Number} referenceValue The reference value for the chart. * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (svg, highLow, options, referenceValue) { + Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) { var i, newMin, newMax, @@ -404,10 +402,6 @@ var Chartist = { low: highLow.low }; - // Overrides of high / low from settings - bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); - bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); - // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity if(bounds.high === bounds.low) { @@ -441,13 +435,13 @@ var Chartist = { // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace // If we are already below the scaleMinSpace value we will scale up - var length = Chartist.projectLength(svg, bounds.step, bounds, options), - scaleUp = length < options.axisY.scaleMinSpace; + var length = Chartist.projectLength(axisLength, bounds.step, bounds), + scaleUp = length < scaleMinSpace; while (true) { - if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { + if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { bounds.step *= 2; - } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { + } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { bounds.step /= 2; } else { break; @@ -506,13 +500,15 @@ var Chartist = { * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ Chartist.createChartRect = function (svg, options) { - var yOffset = options.axisY ? options.axisY.offset : 0, - xOffset = options.axisX ? options.axisX.offset : 0; + var yOffset = options.axisY ? options.axisY.offset || 0 : 0, + xOffset = options.axisX ? options.axisX.offset || 0 : 0, + w = Chartist.stripUnit(options.width) || svg.width(), + h = Chartist.stripUnit(options.height) || svg.height(); return { x1: options.chartPadding + yOffset, - y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), + y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset), y2: options.chartPadding, width: function () { return this.x2 - this.x1; @@ -523,207 +519,81 @@ var Chartist = { }; }; - /** - * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. - * - * @param {Object} parent The SVG element where the label should be created as a child - * @param {String} text The label text - * @param {Object} attributes An object with all attributes that should be set on the label element - * @param {String} className The class names that should be set for this element - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - * @returns {Object} The newly created SVG element - */ - Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { - if(supportsForeignObject) { - var content = '' + text + ''; - return parent.foreignObject(content, attributes); - } else { - return parent.elem('text', attributes, className).text(text); - } + Chartist.createGrid = function(projectedValue, index, axis, offset, length, group, classes, eventEmitter) { + var positionalData = {}; + positionalData[axis.units.pos + '1'] = projectedValue.pos; + positionalData[axis.units.pos + '2'] = projectedValue.pos; + positionalData[axis.counterUnits.pos + '1'] = offset; + positionalData[axis.counterUnits.pos + '2'] = offset + length; + + var gridElement = group.elem('line', positionalData, classes.join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', + Chartist.extend({ + type: 'grid', + axis: axis.units.pos, + index: index, + group: group, + element: gridElement + }, positionalData) + ); }; - /** - * Generate grid lines and labels for the x-axis into grid and labels group SVG elements - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} data The Object that contains the data to be visualized in the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create X-Axis - data.labels.forEach(function (value, index) { - var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)), - height = options.axisX.offset, - pos = chartRect.x1 + width * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { - return; - } - - if (options.axisX.showGrid) { - var gridElement = grid.elem('line', { - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }, [options.classNames.grid, options.classNames.horizontal].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'x', - index: index, - group: grid, - element: gridElement, - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }); - } + Chartist.createLabels = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + var labelElement, + positionalData = {}; + positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; + positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; + positionalData[axis.units.len] = projectedValue.len; + positionalData[axis.counterUnits.len] = axisOffset; + + if(useForeignObject) { + var content = '' + labels[index] + ''; + labelElement = group.foreignObject(content, Chartist.extend({ + style: 'overflow: visible;' + }, positionalData)); + } else { + labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]); + } - if (options.axisX.showLabel) { - var labelPosition = { - x: pos + options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); - - eventEmitter.emit('draw', { - type: 'label', - axis: 'x', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.width; - } - }); - } - }); + eventEmitter.emit('draw', Chartist.extend({ + type: 'label', + axis: axis, + index: index, + group: group, + element: labelElement, + text: labels[index] + }, positionalData)); }; - /** - * Generate grid lines and labels for the y-axis into grid and labels group SVG elements - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create Y-Axis - bounds.values.forEach(function (value, index) { - var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - width = options.axisY.offset, - height = chartRect.height() / bounds.values.length, - pos = chartRect.y1 - height * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { + Chartist.drawAxis = function(axis, data, transform, chartRect, gridGroup, gridOffset, labelGroup, labelOffset, useForeignObject, options, eventEmitter) { + var axisOptions = options['axis' + axis.units.pos.toUpperCase()], + projectedValues = data.map(axis.projectValue.bind(axis)).map(transform), + labelValues = data.map(axisOptions.labelInterpolationFnc); + + projectedValues.forEach(function(projectedValue, index) { + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + if(!labelValues[index] && labelValues[index] !== 0) { return; } - if (options.axisY.showGrid) { - var gridElement = grid.elem('line', { - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }, [options.classNames.grid, options.classNames.vertical].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'y', - index: index, - group: grid, - element: gridElement, - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }); + if(axisOptions.showGrid) { + Chartist.createGrid(projectedValue, index, axis, gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ + options.classNames.grid, + options.classNames[axis.units.dir] + ], eventEmitter); } - if (options.axisY.showLabel) { - var labelPosition = { - x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), - y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); - - eventEmitter.emit('draw', { - type: 'label', - axis: 'y', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.height; - } - }); + if(axisOptions.showLabel) { + Chartist.createLabels(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [ + options.classNames.label, + options.classNames[axis.units.dir] + ], useForeignObject, eventEmitter); } }); }; - /** - * Determine the current point on the svg element to draw the data series - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Number} index The index of the current project point - * @param {Object} options The chart options that are used to influence the calculations - * @return {Object} The coordinates object of the current project point containing an x and y number property - */ - Chartist.projectPoint = function (chartRect, bounds, data, index, options) { - return { - x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index, - y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) - }; - }; - // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one /** * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches diff --git a/tasks/jasmine.js b/tasks/jasmine.js index a7ea3e4a..958dd53b 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -18,6 +18,9 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/scripts/class.js', '<%= pkg.config.src %>/scripts/base.js', '<%= pkg.config.src %>/scripts/svg.js', + '<%= pkg.config.src %>/scripts/axes/axis.js', + '<%= pkg.config.src %>/scripts/axes/step-axis.js', + '<%= pkg.config.src %>/scripts/axes/linear-scale-axis.js', '<%= pkg.config.src %>/scripts/charts/line.js', '<%= pkg.config.src %>/scripts/charts/bar.js', '<%= pkg.config.src %>/scripts/charts/pie.js' From ee5d960c890f2d1d3b183a738b9e097bd0317fe9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 27 Jan 2015 23:03:31 +0100 Subject: [PATCH 163/593] Fixed scope issues --- src/scripts/charts/line.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 35494e84..7db6a0dc 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -181,12 +181,10 @@ (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - var p, - pathCoordinates = [], - point; + var pathCoordinates = []; normalizedData[seriesIndex].forEach(function(value, valueIndex) { - p = { + var p = { x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos }; @@ -195,7 +193,7 @@ //If we should show points we need to create them now to avoid secondary loop // Small offset for Firefox to render squares correctly if (options.showPoint) { - point = seriesGroups[seriesIndex].elem('line', { + var point = seriesGroups[seriesIndex].elem('line', { x1: p.x, y1: p.y, x2: p.x + 0.01, From 3f5e1e56410e37546660885d7ba093ff31ca0826 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 27 Jan 2015 23:35:10 +0100 Subject: [PATCH 164/593] Extracted generic meta data function, fixes #161 --- src/scripts/charts/bar.js | 4 +- src/scripts/charts/line.js | 4 +- src/scripts/core.js | 5 ++ test/spec/spec-bar-chart.js | 98 ++++++++++++++++++++++++++++++++++++ test/spec/spec-line-chart.js | 90 +++++++++++++++++++++++++++++++-- 5 files changed, 191 insertions(+), 10 deletions(-) create mode 100644 test/spec/spec-bar-chart.js diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index e82fe4b9..013b2fa6 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -223,9 +223,7 @@ y2: y2 }, options.classNames.bar).attr({ 'value': value, - 'meta': series.data ? - Chartist.serialize(series.data[valueIndex].meta) : - Chartist.serialize(series[valueIndex].meta) + 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 7db6a0dc..6cd139cb 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -200,9 +200,7 @@ y2: p.y }, options.classNames.point).attr({ 'value': value, - 'meta': series.data ? - Chartist.serialize(series.data[valueIndex].meta) : - Chartist.serialize(series[valueIndex].meta) + 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { diff --git a/src/scripts/core.js b/src/scripts/core.js index f5ce0d59..76a42dab 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -317,6 +317,11 @@ var Chartist = { return dataArray; }; + Chartist.getMetaData = function(series, index) { + var value = series.data ? series.data[index] : series[index]; + return value ? Chartist.serialize(value.meta) : undefined; + }; + /** * Calculate the order of magnitude for the chart scale * diff --git a/test/spec/spec-bar-chart.js b/test/spec/spec-bar-chart.js new file mode 100644 index 00000000..e110b7a0 --- /dev/null +++ b/test/spec/spec-bar-chart.js @@ -0,0 +1,98 @@ +describe('Bar chart tests', function() { + 'use strict'; + + beforeEach(function() { + + }); + + afterEach(function() { + + }); + + describe('Meta data tests', function () { + it('should render meta data correctly with mixed value array', function(done) { + jasmine.getFixtures().set('
    '); + + var meta = { + test: 'Serialized Test' + }; + + var data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + var chart = new Chartist.Bar('.ct-chart', data); + + chart.on('created', function() { + expect(Chartist.deserialize($('.ct-bar').eq(3).attr('ct:meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and different normalized data length', function(done) { + jasmine.getFixtures().set('
    '); + + var meta = { + test: 'Serialized Test' + }; + + var data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + var chart = new Chartist.Bar('.ct-chart', data); + + chart.on('created', function() { + expect(Chartist.deserialize($('.ct-bar').eq(3).attr('ct:meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and mixed series notation', function(done) { + jasmine.getFixtures().set('
    '); + + var seriesMeta = 9999, + valueMeta = { + test: 'Serialized Test' + }; + + var data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: valueMeta + }, 0], + { + meta: seriesMeta, + data: [5, 2, { + value: 2, + meta: valueMeta + }, 0] + } + ] + }; + + var chart = new Chartist.Bar('.ct-chart', data); + + chart.on('created', function() { + expect(Chartist.deserialize($('.ct-series-a .ct-bar').eq(3).attr('ct:meta'))).toEqual(valueMeta); + expect(Chartist.deserialize($('.ct-series-b')).attr('ct:meta')).toEqual(''+seriesMeta); + expect(Chartist.deserialize($('.ct-series-b .ct-bar').eq(2).attr('ct:meta'))).toEqual(valueMeta); + done(); + }); + }); + }); +}); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index e57678ee..ea71a321 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -1,4 +1,3 @@ -//TODO: Add tests! describe('Line chart tests', function() { 'use strict'; @@ -10,7 +9,90 @@ describe('Line chart tests', function() { }); - it('should not give an error because we have 0% test coverage ;-)', function() { - expect(true).toBe(true); + describe('Meta data tests', function () { + it('should render meta data correctly with mixed value array', function(done) { + jasmine.getFixtures().set('
    '); + + var meta = { + test: 'Serialized Test' + }; + + var data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + var chart = new Chartist.Line('.ct-chart', data); + + chart.on('created', function() { + expect(Chartist.deserialize($('.ct-point').eq(3).attr('ct:meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and different normalized data length', function(done) { + jasmine.getFixtures().set('
    '); + + var meta = { + test: 'Serialized Test' + }; + + var data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + var chart = new Chartist.Line('.ct-chart', data); + + chart.on('created', function() { + expect(Chartist.deserialize($('.ct-point').eq(3).attr('ct:meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and mixed series notation', function(done) { + jasmine.getFixtures().set('
    '); + + var seriesMeta = 9999, + valueMeta = { + test: 'Serialized Test' + }; + + var data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: valueMeta + }, 0], + { + meta: seriesMeta, + data: [5, 2, { + value: 2, + meta: valueMeta + }, 0] + } + ] + }; + + var chart = new Chartist.Line('.ct-chart', data); + + chart.on('created', function() { + expect(Chartist.deserialize($('.ct-series-a .ct-point').eq(3).attr('ct:meta'))).toEqual(valueMeta); + expect(Chartist.deserialize($('.ct-series-b')).attr('ct:meta')).toEqual(''+seriesMeta); + expect(Chartist.deserialize($('.ct-series-b .ct-point').eq(2).attr('ct:meta'))).toEqual(valueMeta); + done(); + }); + }); }); -}); \ No newline at end of file +}); From ba55210f6899cd2d30a7b244b70654813b5674ad Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 31 Jan 2015 13:41:08 +0100 Subject: [PATCH 165/593] Removing animation for make the example simpler --- site/examples/behavior-with-jquery.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/site/examples/behavior-with-jquery.js b/site/examples/behavior-with-jquery.js index 4f72957b..b9c77adf 100644 --- a/site/examples/behavior-with-jquery.js +++ b/site/examples/behavior-with-jquery.js @@ -12,10 +12,6 @@ new Chartist.Line('.ct-chart', { ] }); -var easeOutQuad = function (x, t, b, c, d) { - return -c * (t /= d) * (t - 2) + b; -}; - var $chart = $('.ct-chart'); var $toolTip = $chart @@ -27,15 +23,10 @@ $chart.on('mouseenter', '.ct-point', function() { var $point = $(this), value = $point.attr('ct:value'), seriesName = $point.parent().attr('ct:series-name'); - - $point.animate({'stroke-width': '50px'}, 300, easeOutQuad); $toolTip.html(seriesName + '
    ' + value).show(); }); $chart.on('mouseleave', '.ct-point', function() { - var $point = $(this); - - $point.animate({'stroke-width': '20px'}, 300, easeOutQuad); $toolTip.hide(); }); From 89dc45124617fb47690ddc151bc9cdaa36b297e1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 31 Jan 2015 13:44:20 +0100 Subject: [PATCH 166/593] Fixed label offset isssue in example --- site/examples/simple-configuration-chart.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/examples/simple-configuration-chart.js b/site/examples/simple-configuration-chart.js index 7d3b8ced..21eb36d3 100644 --- a/site/examples/simple-configuration-chart.js +++ b/site/examples/simple-configuration-chart.js @@ -24,7 +24,7 @@ var options = { // Y-Axis specific configuration axisY: { // Lets offset the chart a bit from the labels - offset: 40, + offset: 60, // The label interpolation function enables you to modify the values // used for the labels on each axis. Here we are converting the // values into million pound. @@ -35,4 +35,4 @@ var options = { }; // All you need to do is pass your configuration as third parameter to the chart function -new Chartist.Line('.ct-chart', data, options); \ No newline at end of file +new Chartist.Line('.ct-chart', data, options); From 79b0dd5294e6a0e146d56dbeb020273b9bde0cda Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 31 Jan 2015 14:31:14 +0100 Subject: [PATCH 167/593] Integrated option to create horizontal bar chart using the new axis classes, fixes #26 --- site/data/pages/examples.yml | 18 ++ site/examples/bi-polar-bar-interpolated.js | 4 +- .../example-bar-extreme-responsive.js | 46 +++++ site/examples/example-bar-horizontal.js | 14 ++ src/scripts/axes/axis.js | 18 +- src/scripts/axes/linear-scale-axis.js | 10 +- src/scripts/axes/step-axis.js | 6 +- src/scripts/charts/bar.js | 179 +++++++++++------- src/scripts/charts/line.js | 48 ++--- src/scripts/charts/pie.js | 6 +- src/scripts/core.js | 82 +++++++- 11 files changed, 313 insertions(+), 118 deletions(-) create mode 100644 site/examples/example-bar-extreme-responsive.js create mode 100644 site/examples/example-bar-horizontal.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 4568fd75..48eb21cc 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -119,6 +119,24 @@ sections: intro: > You can also set your bar chart to stack the series bars on top of each other easily by using the stackBars property in your configuration. + - type: live-example + data: + title: Horizontal bar chart + level: 4 + id: example-bar-horizontal + classes: ct-golden-section + intro: > + Guess what! Creating horizontal bar charts is as simple as it can get. There's no new chart type + you need to learn, just passing an additional option is enough. + - type: live-example + data: + title: Extreme responsive configuration + level: 4 + id: example-bar-extreme-responsive + classes: ct-golden-section + intro: > + As all settings of a chart can be customized with the responsive configuration override mechanism of + Chartist, you can create a chart that adopts to every media condition! - title: Pie chart examples level: 3 items: diff --git a/site/examples/bi-polar-bar-interpolated.js b/site/examples/bi-polar-bar-interpolated.js index 50fcd752..e78b0484 100644 --- a/site/examples/bi-polar-bar-interpolated.js +++ b/site/examples/bi-polar-bar-interpolated.js @@ -12,9 +12,7 @@ var options = { labelInterpolationFnc: function(value, index) { return index % 2 === 0 ? value : null; } - }, - fullWidth: true, - centerBars: false + } }; new Chartist.Bar('.ct-chart', data, options); diff --git a/site/examples/example-bar-extreme-responsive.js b/site/examples/example-bar-extreme-responsive.js new file mode 100644 index 00000000..6aa8225b --- /dev/null +++ b/site/examples/example-bar-extreme-responsive.js @@ -0,0 +1,46 @@ +new Chartist.Bar('.ct-chart', { + labels: ['Quarter 1', 'Quarter 2', 'Quarter 3', 'Quarter 4'], + series: [ + [5, 4, 3, 7], + [3, 2, 9, 5], + [1, 5, 8, 4], + [2, 3, 4, 6], + [4, 1, 2, 1] + ] +}, { + // Default mobile configuration + stackBars: true, + axisX: { + labelInterpolationFnc: function(value) { + return value.split(/\s+/).map(function(word) { + return word[0]; + }).join(''); + } + }, + axisY: { + offset: 20 + } +}, [ + // Options override for media > 400px + ['screen and (min-width: 400px)', { + reverseData: true, + horizontalBars: true, + axisX: { + labelInterpolationFnc: Chartist.noop + }, + axisY: { + offset: 60 + } + }], + // Options override for media > 800px + ['screen and (min-width: 800px)', { + stackBars: false, + seriesBarDistance: 10 + }], + // Options override for media > 1000px + ['screen and (min-width: 1000px)', { + reverseData: false, + horizontalBars: false, + seriesBarDistance: 15 + }] +]); diff --git a/site/examples/example-bar-horizontal.js b/site/examples/example-bar-horizontal.js new file mode 100644 index 00000000..b70fa008 --- /dev/null +++ b/site/examples/example-bar-horizontal.js @@ -0,0 +1,14 @@ +new Chartist.Bar('.ct-chart', { + labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], + series: [ + [5, 4, 3, 7, 5, 10, 3], + [3, 2, 9, 5, 4, 6, 4] + ] +}, { + seriesBarDistance: 10, + reverseData: true, + horizontalBars: true, + axisY: { + offset: 70 + } +}); diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index e3e8439c..4877a887 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -11,19 +11,29 @@ x: { pos: 'x', len: 'width', - dir: 'horizontal' + dir: 'horizontal', + rectStart: 'x1', + rectEnd: 'x2', + rectOffset: 'y2' }, y: { pos: 'y', len: 'height', - dir: 'vertical' + dir: 'vertical', + rectStart: 'y2', + rectEnd: 'y1', + rectOffset: 'x1' } }; - function Axis(units, axisLength, options) { + function Axis(units, chartRect, transform, labelOffset, options) { this.units = units; this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; - this.axisLength = axisLength; + this.chartRect = chartRect; + this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; + this.gridOffset = chartRect[units.rectOffset]; + this.transform = transform; + this.labelOffset = labelOffset; this.options = options; } diff --git a/src/scripts/axes/linear-scale-axis.js b/src/scripts/axes/linear-scale-axis.js index e2912270..7c5d55dd 100644 --- a/src/scripts/axes/linear-scale-axis.js +++ b/src/scripts/axes/linear-scale-axis.js @@ -1,16 +1,18 @@ /** - * Step axis for step based charts like bar chart or step based line chart + * The linear scale axis uses standard linear scale projection of values along an axis. * - * @module Chartist.StepAxis + * @module Chartist.LinearScaleAxis */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; - function LinearScaleAxis(axisUnit, axisLength, options) { + function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) { Chartist.LinearScaleAxis.super.constructor.call(this, axisUnit, - axisLength, + chartRect, + transform, + labelOffset, options); this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index df6a2064..d84b647c 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -7,10 +7,12 @@ (function (window, document, Chartist) { 'use strict'; - function StepAxis(axisUnit, axisLength, options) { + function StepAxis(axisUnit, chartRect, transform, labelOffset, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, - axisLength, + chartRect, + transform, + labelOffset, options); this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 013b2fa6..b306e2e2 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -27,7 +27,9 @@ // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop + labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum width in pixel of the scale steps + scaleMinSpace: 40 }, // Options for Y-Axis axisY: { @@ -59,12 +61,12 @@ chartPadding: 5, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, - // 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. For bar charts this might be used in conjunction with the centerBars property set to false. - fullWidth: false, - // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property. - centerBars: true, // If set to true this property will cause the series bars to be stacked and 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. stackBars: false, + // 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. + horizontalBars: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', @@ -85,8 +87,7 @@ */ function createChart(options) { var seriesGroups = [], - projectedValues, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length), + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), highLow; // Create new svg element @@ -108,65 +109,105 @@ var chartRect = Chartist.createChartRect(this.svg, options); - var axisX = new Chartist.StepAxis( - Chartist.Axis.units.x, - chartRect.x2 - chartRect.x1, { - stepCount: this.data.labels.length, - stretch: options.fullWidth - } - ); + var valueAxis, + labelAxis; - var axisY = new Chartist.LinearScaleAxis( - Chartist.Axis.units.y, - chartRect.y1 - chartRect.y2, { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - referenceValue: 0 - } - ); + if(options.horizontalBars) { + labelAxis = new Chartist.StepAxis( + Chartist.Axis.units.y, + chartRect, + function timeAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length + }, + { + stepCount: this.data.labels.length, + stretch: options.fullHeight + } + ); + + valueAxis = new Chartist.LinearScaleAxis( + Chartist.Axis.units.x, + chartRect, + function valueAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { + highLow: highLow, + scaleMinSpace: options.axisX.scaleMinSpace, + referenceValue: 0 + } + ); + } else { + labelAxis = new Chartist.StepAxis( + Chartist.Axis.units.x, + chartRect, + function timeAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { + stepCount: this.data.labels.length + } + ); + + valueAxis = new Chartist.LinearScaleAxis( + Chartist.Axis.units.y, + chartRect, + function valueAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) + }, + { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace, + referenceValue: 0 + } + ); + } // Start drawing var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup), // Projected 0 point - zeroPoint = chartRect.y1 - axisY.projectValue(0).pos, + zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos), // Used to track the screen coordinates of stacked bars stackedBarValues = []; - Chartist.drawAxis( - axisX, + Chartist.createAxis( + labelAxis, this.data.labels, - function(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, chartRect, gridGroup, - chartRect.y2, labelGroup, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, this.supportsForeignObject, options, this.eventEmitter ); - Chartist.drawAxis( - axisY, - axisY.bounds.values, - function(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, + Chartist.createAxis( + valueAxis, + valueAxis.bounds.values, chartRect, gridGroup, - chartRect.x1, - labelGroup, { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) - }, + labelGroup, this.supportsForeignObject, options, this.eventEmitter @@ -177,7 +218,7 @@ // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. var biPol = seriesIndex - (this.data.series.length - 1) / 2, // Half of the period width between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / (normalizedData[seriesIndex].length - (options.fullWidth ? 1 : 0)) / 2; + periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2; seriesGroups[seriesIndex] = this.svg.elem('g'); @@ -194,54 +235,46 @@ ].join(' ')); normalizedData[seriesIndex].forEach(function(value, valueIndex) { - var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos - }, + var projected = { + x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + }, bar, - previousStack, - y1, - y2; + previousStack; // Offset to center bar between grid lines - p.x += (options.centerBars ? periodHalfWidth : 0); + projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); // Using bi-polar offset for multiple series if no stacked bars are used - p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance; + projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); // Enter value in stacked bar values used to remember previous screen value for stacking up bars previousStack = stackedBarValues[valueIndex] || zeroPoint; - stackedBarValues[valueIndex] = previousStack - (zeroPoint - p.y); + stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); + var positions = {}; + positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; + positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - y1 = options.stackBars ? previousStack : zeroPoint; - y2 = options.stackBars ? stackedBarValues[valueIndex] : p.y; + positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; - bar = seriesGroups[seriesIndex].elem('line', { - x1: p.x, - y1: y1, - x2: p.x, - y2: y2 - }, options.classNames.bar).attr({ + bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({ 'value': value, 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); - this.eventEmitter.emit('draw', { + this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', value: value, index: valueIndex, group: seriesGroups[seriesIndex], - element: bar, - x1: p.x, - y1: y1, - x2: p.x, - y2: y2 - }); + element: bar + }, positions)); }.bind(this)); }.bind(this)); this.eventEmitter.emit('created', { - bounds: axisY.bounds, + bounds: valueAxis.bounds, chartRect: chartRect, svg: this.svg, options: options diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 6cd139cb..c7532624 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -71,6 +71,8 @@ chartPadding: 5, // 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. fullWidth: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-line', @@ -93,7 +95,7 @@ */ function createChart(options) { var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); @@ -107,7 +109,16 @@ var axisX = new Chartist.StepAxis( Chartist.Axis.units.x, - chartRect.x2 - chartRect.x1, { + chartRect, + function xAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { stepCount: this.data.labels.length, stretch: options.fullWidth } @@ -115,7 +126,16 @@ var axisY = new Chartist.LinearScaleAxis( Chartist.Axis.units.y, - chartRect.y1 - chartRect.y2, { + chartRect, + function yAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) + }, + { highLow: highLow, scaleMinSpace: options.axisY.scaleMinSpace } @@ -125,41 +145,23 @@ var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); - Chartist.drawAxis( + Chartist.createAxis( axisX, this.data.labels, - function(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, chartRect, gridGroup, - chartRect.y2, labelGroup, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, this.supportsForeignObject, options, this.eventEmitter ); - Chartist.drawAxis( + Chartist.createAxis( axisY, axisY.bounds.values, - function(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, chartRect, gridGroup, - chartRect.x1, labelGroup, - { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) - }, this.supportsForeignObject, options, this.eventEmitter diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index dbfc757f..e1184355 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -42,7 +42,9 @@ // An interpolation function for the label value labelInterpolationFnc: Chartist.noop, // 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. - labelDirection: 'neutral' + labelDirection: 'neutral', + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false }; /** @@ -79,7 +81,7 @@ labelRadius, totalDataSum, startAngle = options.startAngle, - dataArray = Chartist.getDataArray(this.data); + dataArray = Chartist.getDataArray(this.data, options.reverseData); // Create SVG.js draw this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); diff --git a/src/scripts/core.js b/src/scripts/core.js index 76a42dab..db8797c1 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -259,18 +259,46 @@ var Chartist = { return svg; }; + + /** + * Reverses the series, labels and series data arrays. + * + * @memberof Chartist.Core + * @param data + */ + Chartist.reverseData = function(data) { + data.labels.reverse(); + data.series.reverse(); + for (var i = 0; i < data.series.length; i++) { + if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { + data.series[i].data.reverse(); + } else { + data.series[i].reverse(); + } + } + }; + /** * Convert data series into plain array * * @memberof Chartist.Core * @param {Object} data The series object that contains the data to be visualized in the chart + * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ - Chartist.getDataArray = function (data) { + Chartist.getDataArray = function (data, reverse) { var array = [], value, localData; + // If the data should be reversed but isn't we need to reverse it + // If it's reversed but it shouldn't we need to reverse it back + // That's required to handle data updates correctly and to reflect the responsive configurations + if(reverse && !data.reversed || !reverse && data.reversed) { + Chartist.reverseData(data); + data.reversed = !data.reversed; + } + for (var i = 0; i < data.series.length; i++) { // If the series array contains an object with a data property we will use the property // otherwise the value directly (array or number). @@ -524,6 +552,19 @@ var Chartist = { }; }; + /** + * Creates a grid line based on a projected value. + * + * @memberof Chartist.Core + * @param projectedValue + * @param index + * @param axis + * @param offset + * @param length + * @param group + * @param classes + * @param eventEmitter + */ Chartist.createGrid = function(projectedValue, index, axis, offset, length, group, classes, eventEmitter) { var positionalData = {}; positionalData[axis.units.pos + '1'] = projectedValue.pos; @@ -545,7 +586,22 @@ var Chartist = { ); }; - Chartist.createLabels = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + /** + * Creates a label based on a projected value and an axis. + * + * @memberof Chartist.Core + * @param projectedValue + * @param index + * @param labels + * @param axis + * @param axisOffset + * @param labelOffset + * @param group + * @param classes + * @param useForeignObject + * @param eventEmitter + */ + Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { var labelElement, positionalData = {}; positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; @@ -572,9 +628,22 @@ var Chartist = { }, positionalData)); }; - Chartist.drawAxis = function(axis, data, transform, chartRect, gridGroup, gridOffset, labelGroup, labelOffset, useForeignObject, options, eventEmitter) { + /** + * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect. + * + * @memberof Chartist.Core + * @param axis + * @param data + * @param chartRect + * @param gridGroup + * @param labelGroup + * @param useForeignObject + * @param options + * @param eventEmitter + */ + Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { var axisOptions = options['axis' + axis.units.pos.toUpperCase()], - projectedValues = data.map(axis.projectValue.bind(axis)).map(transform), + projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform), labelValues = data.map(axisOptions.labelInterpolationFnc); projectedValues.forEach(function(projectedValue, index) { @@ -584,14 +653,14 @@ var Chartist = { } if(axisOptions.showGrid) { - Chartist.createGrid(projectedValue, index, axis, gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ + Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ options.classNames.grid, options.classNames[axis.units.dir] ], eventEmitter); } if(axisOptions.showLabel) { - Chartist.createLabels(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [ + Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [ options.classNames.label, options.classNames[axis.units.dir] ], useForeignObject, eventEmitter); @@ -599,7 +668,6 @@ var Chartist = { }); }; - // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one /** * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches * From e927adfdf9e973a0a7610b1b6692fb2933d7cb9d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 31 Jan 2015 18:45:27 +0100 Subject: [PATCH 168/593] Fixed issues with 0 values in series object data notation, fixes #172 --- src/scripts/core.js | 3 +-- test/spec/spec-core.js | 60 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index db8797c1..b20d6876 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -311,11 +311,10 @@ var Chartist = { array[i] = localData; } - // Convert object values to numbers for (var j = 0; j < array[i].length; j++) { value = array[i][j]; - value = value.value || value; + value = value.value === 0 ? 0 : (value.value || value); array[i][j] = +value; } } diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 41747a3d..9f4ac92d 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -82,4 +82,64 @@ describe('Chartist core', function() { expect(NaN).toMatch(Chartist.deserialize(Chartist.serialize('NaN'))); }); }); + + describe('data normalization tests', function () { + it('should normalize based on label length', function() { + var data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [1, 2, 3, 4, 5, 6], + [1, 2, 3, 4, 5, 6, 7, 8], + [1, 2, 3] + ] + }; + + expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( + [ + [1, 2, 3, 4, 5, 6, 0, 0, 0, 0], + [1, 2, 3, 4, 5, 6, 7, 8, 0, 0], + [1, 2, 3, 0, 0, 0, 0, 0, 0, 0] + ] + ); + }); + + it('normalize mixed series types correctly', function() { + var data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + {data: [1, 0, 3, 4, 5, 6]}, + [1, {value: 0}, 3, {value: 4}, 5, 6, 7, 8], + {data: [1, 0, {value: 3}]} + ] + }; + + expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( + [ + [1, 0, 3, 4, 5, 6, 0, 0, 0, 0], + [1, 0, 3, 4, 5, 6, 7, 8, 0, 0], + [1, 0, 3, 0, 0, 0, 0, 0, 0, 0] + ] + ); + }); + + it('should normalize correctly with 0 values in data series array objects', function() { + var data = { + labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + series: [{ + data: [ + { value: 1 }, + { value: 4 }, + { value: 2 }, + { value: 7 }, + { value: 2 }, + { value: 0 } + ] + }] + }; + + expect(Chartist.normalizeDataArray(Chartist.getDataArray(data))).toEqual( + [[1, 4, 2, 7, 2, 0]] + ); + }); + }); }); From bc9030d860ccc19acf192ddc1e64030739d5b6b1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 31 Jan 2015 19:02:35 +0100 Subject: [PATCH 169/593] Updating after options update enables the use of 'print' media query in responsive options to have a quick redraw before printing, only works in Chrome 40 so far --- src/scripts/base.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scripts/base.js b/src/scripts/base.js index b3d1909f..2ae51dc4 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -92,6 +92,10 @@ // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + // Register options change listener that will trigger a chart update + this.eventEmitter.addEventHandler('optionsChanged', function() { + this.update(); + }.bind(this)); // Before the first chart creation we need to register us with all plugins that are configured // Initialize all relevant plugins with our chart object and the plugin options specified in the config From 8368873ae95a7a0b21134e2d8fb432723bad96a0 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 1 Feb 2015 03:06:47 +0100 Subject: [PATCH 170/593] Added SVG Path API for manipulating SVG paths, fixes #173 --- site/data/pages/examples.yml | 9 + site/examples/example-line-path-animation.js | 26 ++ site/layouts/default.hbs | 1 + src/scripts/charts/bar.js | 1 + src/scripts/charts/line.js | 32 +- src/scripts/svg-path.js | 303 +++++++++++++++++++ tasks/concat.js | 1 + test/spec/spec-svg.js | 139 +++++++++ 8 files changed, 499 insertions(+), 13 deletions(-) create mode 100644 site/examples/example-line-path-animation.js create mode 100644 src/scripts/svg-path.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 48eb21cc..1870acaa 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -70,6 +70,15 @@ sections: Chartist provides a simple API to animate the elements on the Chart using SMIL. Usually you can achieve most animation with CSS3 animations but in some cases you'd like to animate SVG properties that are not available in CSS. + - type: live-example + data: + title: SVG Path animation + level: 4 + id: example-line-path-animation + classes: ct-golden-section + intro: > + Path animation is made easy with the SVG Path API. + The API allows you to modify complex SVG paths and transform them for different animation morphing states. - title: Bar chart examples level: 3 items: diff --git a/site/examples/example-line-path-animation.js b/site/examples/example-line-path-animation.js new file mode 100644 index 00000000..66415d42 --- /dev/null +++ b/site/examples/example-line-path-animation.js @@ -0,0 +1,26 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + series: [ + [1, 5, 2, 5, 4, 3], + [2, 3, 4, 8, 1, 2], + [5, 4, 3, 2, 1, 0.5] + ] +}, { + low: 0, + showArea: true, + showPoint: false +}); + +chart.on('draw', function(data) { + if(data.type === 'line' || data.type === 'area') { + data.element.animate({ + d: { + begin: 2000 * data.index, + dur: 2000, + from: data.path.clone().scale(1, 0).translate(0, data.chartRect.height()).stringify(), + to: data.path.clone().stringify(), + easing: Chartist.Svg.Easing.easeOutQuint + } + }); + } +}); diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 13568037..581ad6e7 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -56,6 +56,7 @@ + diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index b306e2e2..59b2a600 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -267,6 +267,7 @@ type: 'bar', value: value, index: valueIndex, + chartRect: chartRect, group: seriesGroups[seriesIndex], element: bar }, positions)); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index c7532624..1f463729 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -219,25 +219,24 @@ // TODO: Nicer handling of conditions, maybe composition? if (options.showLine || options.showArea) { - // TODO: We should add a path API in the SVG library for easier path creation - var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); // If smoothed path and path has more than two points then use catmull rom to bezier algorithm if (options.lineSmooth && pathCoordinates.length > 4) { var cr = Chartist.catmullRom2bezier(pathCoordinates); for(var k = 0; k < cr.length; k++) { - pathElements.push('C' + cr[k].join()); + Chartist.Svg.Path.prototype.curve.apply(path, cr[k]); } } else { for(var l = 3; l < pathCoordinates.length; l += 2) { - pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); + path.line(pathCoordinates[l - 1], pathCoordinates[l]); } } if(options.showLine) { var line = seriesGroups[seriesIndex].elem('path', { - d: pathElements.join('') + d: path.stringify() }, options.classNames.line, true).attr({ 'values': normalizedData[seriesIndex] }, Chartist.xmlNs.uri); @@ -245,6 +244,8 @@ this.eventEmitter.emit('draw', { type: 'line', values: normalizedData[seriesIndex], + path: path.clone(), + chartRect: chartRect, index: seriesIndex, group: seriesGroups[seriesIndex], element: line @@ -256,19 +257,22 @@ // the area is not drawn outside the chart area. var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); - // If we need to draw area shapes we just make a copy of our pathElements SVG path array - var areaPathElements = pathElements.slice(); - // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; - // And splice our new area path array to add the missing path elements to close the area shape - areaPathElements.splice(0, 0, 'M' + chartRect.x1 + ',' + areaBaseProjected); - areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; - areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected); + + // Clone original path and splice our new area path to add the missing path elements to close the area shape + var areaPath = path.clone(); + // Modify line path and add missing elements for area + areaPath.position(0) + .remove(1) + .move(chartRect.x1, areaBaseProjected) + .line(pathCoordinates[0], pathCoordinates[1]) + .position(areaPath.pathElements.length) + .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); // Create the new path for the area shape with the area class from the options var area = seriesGroups[seriesIndex].elem('path', { - d: areaPathElements.join('') + d: areaPath.stringify() }, options.classNames.area, true).attr({ 'values': normalizedData[seriesIndex] }, Chartist.xmlNs.uri); @@ -276,6 +280,8 @@ this.eventEmitter.emit('draw', { type: 'area', values: normalizedData[seriesIndex], + path: areaPath.clone(), + chartRect: chartRect, index: seriesIndex, group: seriesGroups[seriesIndex], element: area diff --git a/src/scripts/svg-path.js b/src/scripts/svg-path.js new file mode 100644 index 00000000..cbaaba06 --- /dev/null +++ b/src/scripts/svg-path.js @@ -0,0 +1,303 @@ +/** + * Chartist SVG path module for SVG path description creation and modification. + * + * @module Chartist.Svg.Path + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + /** + * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported. + * + * @memberof Chartist.Svg.Path + * @type {Object} + */ + var elementDescriptions = { + m: ['x', 'y'], + l: ['x', 'y'], + c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'] + }; + + /** + * Default options for newly created SVG path objects. + * + * @memberof Chartist.Svg.Path + * @type {Object} + */ + var defaultOptions = { + // 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. + accuracy: 3 + }; + + function element(command, params, pathElements, pos, relative) { + pathElements.splice(pos, 0, Chartist.extend({ + command: relative ? command.toLowerCase() : command.toUpperCase() + }, params)); + } + + function forEachParam(pathElements, cb) { + pathElements.forEach(function(pathElement, pathElementIndex) { + elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) { + cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + }); + }); + } + + /** + * Used to construct a new path object. + * + * @memberof Chartist.Svg.Path + * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end) + * @param {Object} options Options object that overrides the default objects. See default options for more details. + * @constructor + */ + function SvgPath(close, options) { + this.pathElements = []; + this.pos = 0; + this.close = close; + this.options = Chartist.extend({}, defaultOptions, options); + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} [position] If a number is passed then the cursor is set to this position in the path element array. + * @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. + */ + function position(pos) { + if(pos !== undefined) { + this.pos = Math.max(0, Math.min(this.pathElements.length, pos)); + return this; + } else { + return this.pos; + } + } + + /** + * Removes elements from the path starting at the current position. + * + * @memberof Chartist.Svg.Path + * @param {Number} count Number of path elements that should be removed from the current position. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function remove(count) { + this.pathElements.splice(this.pos, count); + return this; + } + + /** + * Use this function to add a new move SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The x coordinate for the move element. + * @param {Number} y The y coordinate for the move element. + * @param {Boolean} relative If set to true the move element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function move(x, y, relative) { + element('M', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * Use this function to add a new line SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The x coordinate for the line element. + * @param {Number} y The y coordinate for the line element. + * @param {Boolean} relative If set to true the line element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function line(x, y, relative) { + element('L', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * Use this function to add a new curve SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x1 The x coordinate for the first control point of the bezier curve. + * @param {Number} y1 The y coordinate for the first control point of the bezier curve. + * @param {Number} x2 The x coordinate for the second control point of the bezier curve. + * @param {Number} y2 The y coordinate for the second control point of the bezier curve. + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} relative If set to true the curve element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function curve(x1, y1, x2, y2, x, y, relative) { + element('C', { + x1: +x1, + y1: +y1, + x2: +x2, + y2: +y2, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function parse(path) { + // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] + var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') + .replace(/([0-9])([A-Za-z])/g, '$1 $2') + .split(/[\s,]+/) + .reduce(function(result, element) { + if(element.match(/[A-Za-z]/)) { + result.push([]); + } + + result[result.length - 1].push(element); + return result; + }, []); + + // If this is a closed path we remove the Z at the end because this is determined by the close option + if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') { + chunks.pop(); + } + + // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters + // For example {command: 'M', x: '10', y: '10'} + var elements = chunks.map(function(chunk) { + var command = chunk.shift(), + description = elementDescriptions[command.toLowerCase()]; + + return Chartist.extend({ + command: command + }, description.reduce(function(result, paramName, index) { + result[paramName] = +chunk[index]; + return result; + }, {})); + }); + + // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position + var spliceArgs = [this.pos, 0]; + Array.prototype.push.apply(spliceArgs, elements); + Array.prototype.splice.apply(this.pathElements, spliceArgs); + // Increase the internal position by the element count + this.pos += elements.length; + + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @return {String} + */ + function stringify() { + var accuracyMultiplier = Math.pow(10, this.options.accuracy); + + return this.pathElements.reduce(function(path, pathElement) { + var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) { + return this.options.accuracy ? + (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) : + pathElement[paramName]; + }.bind(this)); + + return path + pathElement.command + params.join(','); + }.bind(this), '') + (this.close ? 'Z' : ''); + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function scale(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] *= paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function translate(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] += paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * The method signature of the callback function looks like this: + * ```javascript + * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) + * ``` + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function transform(transformFnc) { + forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) { + var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + if(transformed || transformed === 0) { + pathElement[paramName] = transformed; + } + }); + return this; + } + + /** + * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. + * + * @memberof Chartist.Svg.Path + * @return {Chartist.Svg.Path} + */ + function clone() { + var c = new Chartist.Svg.Path(this.close); + c.pos = this.pos; + c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { + return Chartist.extend({}, pathElement); + }); + c.options = Chartist.extend({}, this.options); + return c; + } + + Chartist.Svg.Path = Chartist.Class.extend({ + constructor: SvgPath, + position: position, + remove: remove, + move: move, + line: line, + curve: curve, + scale: scale, + translate: translate, + transform: transform, + parse: parse, + stringify: stringify, + clone: clone + }); + + Chartist.Svg.Path.elementDescriptions = elementDescriptions; +}(window, document, Chartist)); diff --git a/tasks/concat.js b/tasks/concat.js index 0c7f2178..595bde22 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -23,6 +23,7 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/scripts/class.js', '<%= pkg.config.src %>/scripts/base.js', '<%= pkg.config.src %>/scripts/svg.js', + '<%= pkg.config.src %>/scripts/svg-path.js', '<%= pkg.config.src %>/scripts/charts/line.js', '<%= pkg.config.src %>/scripts/charts/bar.js', '<%= pkg.config.src %>/scripts/charts/pie.js' diff --git a/test/spec/spec-svg.js b/test/spec/spec-svg.js index 4e5fea34..b2cd5f60 100644 --- a/test/spec/spec-svg.js +++ b/test/spec/spec-svg.js @@ -159,4 +159,143 @@ describe('Chartist SVG', function () { expect(svg._node.firstChild.firstChild.firstChild).toBeDefined(); expect(svg._node.firstChild.firstChild.firstChild.attributes.transform.textContent).toBe('rotate(10 10 10)'); }); + + describe('path tests', function () { + it('should handle position updates correctly', function () { + var path = new Chartist.Svg.Path(); + expect(path.position()).toBe(0); + expect(path.position(100).position()).toBe(0); + expect(path.position(-1).position()).toBe(0); + + path.pathElements = [1, 2, 3]; + expect(path.position(100).position()).toBe(3); + }); + + it('should add absolute and relative path elements correctly', function () { + var path = new Chartist.Svg.Path() + .move(1, 2) + .move(3, 4, true) + .line(5, 6) + .line(7, 8, true) + .curve(9, 10, 11, 12, 13, 14) + .curve(15, 16, 17, 18, 19, 20, true); + + expect(path.pathElements.length).toBe(6); + expect(path.pathElements).toEqual([ + { command: 'M', x: 1, y: 2 }, + { command: 'm', x: 3, y: 4 }, + { command: 'L', x: 5, y: 6 }, + { command: 'l', x: 7, y: 8 }, + { command: 'C', x1: 9, y1: 10, x2: 11, y2: 12, x: 13, y: 14 }, + { command: 'c', x1: 15, y1: 16, x2: 17, y2: 18, x: 19, y: 20 } + ]); + }); + + it('should insert new elements at correct position', function () { + var path = new Chartist.Svg.Path() + .move(1, 2) + .move(7, 8) + .move(9, 10) + .position(1) + .move(3, 4) + .move(5, 6) + .position(100000) + .move(11, 12) + .position(-100000) + .move(-1, 0); + + expect(path.pathElements.length).toBe(7); + expect(path.pathElements).toEqual([ + { command: 'M', x: -1, y: 0 }, + { command: 'M', x: 1, y: 2 }, + { command: 'M', x: 3, y: 4 }, + { command: 'M', x: 5, y: 6 }, + { command: 'M', x: 7, y: 8 }, + { command: 'M', x: 9, y: 10 }, + { command: 'M', x: 11, y: 12 } + ]); + }); + + it('should stringify simple shape correctly', function () { + var path = new Chartist.Svg.Path(true).move(10, 10).line(10, 100).line(100, 100).line(100, 10); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10Z'); + }); + + it('should stringify with configured precision', function () { + var path = new Chartist.Svg.Path(false, { + accuracy: 2 + }).move(10.12345, 10.14345).line(10.14545, 10).line(10.14000000645, 10.3333333333); + expect(path.stringify()).toEqual('M10.12,10.14L10.15,10L10.14,10.33'); + }); + + it('should parse Chartist SVG path style correctly', function () { + var path = new Chartist.Svg.Path().parse('M10,10L10,100L100,100L100,10'); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10'); + }); + + it('should parse MDN SVG path style correctly', function () { + var path = new Chartist.Svg.Path().parse('M10 10 L 10 100 L 100 100 L 100 10 C 1 1, 1 1, 1 1'); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10C1,1,1,1,1,1'); + }); + + it('should parse path with closing command', function () { + var path = new Chartist.Svg.Path().parse('M10 10 L 10 100 L 100 100 L 100 10 C 1 1, 1 1, 1 1 Z'); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10C1,1,1,1,1,1'); + }); + + it('should parse complex path correctly', function () { + var path = new Chartist.Svg.Path(false, { + accuracy: false + }).parse('M7.566371681415929,313.5870318472049L15.132743362831858,322.1479887268699L22.699115044247787,292.49058976570063L30.265486725663717,284.9469379116152L37.83185840707964,277.62070141556273L45.39823008849557,285.4043086222666L52.9646017699115,295.16905806058617L60.530973451327434,288.5395967440654L68.09734513274336,282.3023155078293L75.66371681415929,276.9420221519757L83.23008849557522,271.31296300227655L90.79646017699115,273.1827546735411L98.36283185840708,282.72148250847295L105.929203539823,276.55760703185683L113.49557522123892,278.16318930715545L121.06194690265487,279.67913384762466L128.6283185840708,296.53529757775897L136.1946902654867,324.4003397770142L143.76106194690263,317.1376004332516L151.32743362831857,323.3390406432677L158.89380530973452,328.5597479599146L166.46017699115043,329.67851354926904L174.02654867256635,327.71837583373326L181.5929203539823,335.05972598190976L189.15929203539824,334.29372633331286L196.72566371681415,332.68724934321176L204.29203539823007,330.6752327006325L211.858407079646,325.971917329413L219.42477876106196,328.13057177790404L226.99115044247785,309.6546479835954L234.5575221238938,310.6637826993739L242.12389380530973,310.65221523366176L249.69026548672568,318.40285733188773L257.2566371681416,298.18154267575227L264.8230088495575,307.4788389000347L272.3893805309734,304.189264255087L279.95575221238937,289.0288876874009L287.52212389380526,300.20654714775424L295.0884955752212,298.0164127652739L302.65486725663715,287.69192345832175L310.2212389380531,293.1860711045035L317.78761061946904,300.4760502113585L325.3539823008849,297.94852206276937L332.92035398230087,305.6594311405378L340.4867256637168,306.7859423144216L348.0530973451327,275.68998851331963L355.61946902654864,286.5550640745874L363.1858407079646,288.4952543187362L370.75221238938053,290.1896066608983L378.3185840707965,277.8447927515142L385.88495575221236,282.46018876596827L393.4513274336283,261.617847596371L401.01769911504425,265.06101027918726L408.58407079646014,264.60492966286677L416.1504424778761,252.35288845280365L423.716814159292,239.29220756750195L431.283185840708,229.73170018586225L438.8495575221239,224.1580859168795L446.41592920353986,217.20551113129414L453.9823008849557,212.63435660265037L461.54867256637164,210.4425212857057L469.1150442477876,201.0077146146342L476.6814159292035,182.3934004122068L484.24778761061947,176.98732946386616L491.8141592920354,175.3660655079267L499.38053097345136,181.1589144624976L506.9469026548673,172.81581557677976L514.5132743362832,177.82343674256106L522.079646017699,183.5573714672562L529.646017699115,184.4980688436067L537.2123893805309,201.60789339862924L544.7787610619469,193.42268767053048L552.3451327433628,209.9219909677575L559.9115044247787,221.1318944868172L567.4778761061947,222.47350026973174L575.0442477876105,229.94061399967882L582.6106194690265,213.57676800697396L590.1769911504424,232.97280246785252L597.7433628318583,232.8915724787845L605.3097345132743,231.486089735319L612.8761061946902,234.26534000120475L620.4424778761062,219.90951817170736L628.0088495575221,214.36149678900725L635.5752212389381,204.7245641444236L643.1415929203539,205.04759319834227L650.7079646017698,178.61624621480792L658.2743362831858,174.30656351022486L665.8407079646017,194.06864637030463L673.4070796460177,191.38404795482728L680.9734513274336,188.88380371217903L688.5398230088496,182.47430260433697L696.1061946902654,192.70175438596493L703.6725663716813,182.37945067166908L711.2389380530973,163.80499447227572L718.8053097345132,157.4839718811134L726.3716814159292,149.57403342725343L733.9380530973451,142.6076734278762L741.5044247787611,144.9954413314636L749.070796460177,152.29112878815386L756.637168141593,150.02544379977235L764.2035398230088,139.40203164917125L771.7699115044247,149.22935357717972L779.3362831858407,155.78116263659354L786.9026548672566,145.09966219897575L794.4690265486726,157.52407467202426L802.0353982300885,147.01645902195105L809.6017699115044,141.8658056183404L817.1681415929203,134.36135158737966L824.7345132743362,127.49269525433283L832.3008849557522,120.25886939571154L839.8672566371681,118.26230310074709L847.433628318584,98.76959064327474'); + expect(path.stringify()).toEqual('M7.566371681415929,313.5870318472049L15.132743362831858,322.1479887268699L22.699115044247787,292.49058976570063L30.265486725663717,284.9469379116152L37.83185840707964,277.62070141556273L45.39823008849557,285.4043086222666L52.9646017699115,295.16905806058617L60.530973451327434,288.5395967440654L68.09734513274336,282.3023155078293L75.66371681415929,276.9420221519757L83.23008849557522,271.31296300227655L90.79646017699115,273.1827546735411L98.36283185840708,282.72148250847295L105.929203539823,276.55760703185683L113.49557522123892,278.16318930715545L121.06194690265487,279.67913384762466L128.6283185840708,296.53529757775897L136.1946902654867,324.4003397770142L143.76106194690263,317.1376004332516L151.32743362831857,323.3390406432677L158.89380530973452,328.5597479599146L166.46017699115043,329.67851354926904L174.02654867256635,327.71837583373326L181.5929203539823,335.05972598190976L189.15929203539824,334.29372633331286L196.72566371681415,332.68724934321176L204.29203539823007,330.6752327006325L211.858407079646,325.971917329413L219.42477876106196,328.13057177790404L226.99115044247785,309.6546479835954L234.5575221238938,310.6637826993739L242.12389380530973,310.65221523366176L249.69026548672568,318.40285733188773L257.2566371681416,298.18154267575227L264.8230088495575,307.4788389000347L272.3893805309734,304.189264255087L279.95575221238937,289.0288876874009L287.52212389380526,300.20654714775424L295.0884955752212,298.0164127652739L302.65486725663715,287.69192345832175L310.2212389380531,293.1860711045035L317.78761061946904,300.4760502113585L325.3539823008849,297.94852206276937L332.92035398230087,305.6594311405378L340.4867256637168,306.7859423144216L348.0530973451327,275.68998851331963L355.61946902654864,286.5550640745874L363.1858407079646,288.4952543187362L370.75221238938053,290.1896066608983L378.3185840707965,277.8447927515142L385.88495575221236,282.46018876596827L393.4513274336283,261.617847596371L401.01769911504425,265.06101027918726L408.58407079646014,264.60492966286677L416.1504424778761,252.35288845280365L423.716814159292,239.29220756750195L431.283185840708,229.73170018586225L438.8495575221239,224.1580859168795L446.41592920353986,217.20551113129414L453.9823008849557,212.63435660265037L461.54867256637164,210.4425212857057L469.1150442477876,201.0077146146342L476.6814159292035,182.3934004122068L484.24778761061947,176.98732946386616L491.8141592920354,175.3660655079267L499.38053097345136,181.1589144624976L506.9469026548673,172.81581557677976L514.5132743362832,177.82343674256106L522.079646017699,183.5573714672562L529.646017699115,184.4980688436067L537.2123893805309,201.60789339862924L544.7787610619469,193.42268767053048L552.3451327433628,209.9219909677575L559.9115044247787,221.1318944868172L567.4778761061947,222.47350026973174L575.0442477876105,229.94061399967882L582.6106194690265,213.57676800697396L590.1769911504424,232.97280246785252L597.7433628318583,232.8915724787845L605.3097345132743,231.486089735319L612.8761061946902,234.26534000120475L620.4424778761062,219.90951817170736L628.0088495575221,214.36149678900725L635.5752212389381,204.7245641444236L643.1415929203539,205.04759319834227L650.7079646017698,178.61624621480792L658.2743362831858,174.30656351022486L665.8407079646017,194.06864637030463L673.4070796460177,191.38404795482728L680.9734513274336,188.88380371217903L688.5398230088496,182.47430260433697L696.1061946902654,192.70175438596493L703.6725663716813,182.37945067166908L711.2389380530973,163.80499447227572L718.8053097345132,157.4839718811134L726.3716814159292,149.57403342725343L733.9380530973451,142.6076734278762L741.5044247787611,144.9954413314636L749.070796460177,152.29112878815386L756.637168141593,150.02544379977235L764.2035398230088,139.40203164917125L771.7699115044247,149.22935357717972L779.3362831858407,155.78116263659354L786.9026548672566,145.09966219897575L794.4690265486726,157.52407467202426L802.0353982300885,147.01645902195105L809.6017699115044,141.8658056183404L817.1681415929203,134.36135158737966L824.7345132743362,127.49269525433283L832.3008849557522,120.25886939571154L839.8672566371681,118.26230310074709L847.433628318584,98.76959064327474'); + }); + + it('should scale path along both axes', function () { + var path = new Chartist.Svg.Path() + .move(1, 2) + .line(3, 4) + .curve(5, 6, 7, 8, 9, 10) + .scale(10, 100); + + expect(path.pathElements).toEqual([ + { command: 'M', x: 10, y: 200 }, + { command: 'L', x: 30, y: 400 }, + { command: 'C', x1: 50, y1: 600, x2: 70, y2: 800, x: 90, y: 1000 } + ]); + }); + + it('should translate path along both axes', function () { + var path = new Chartist.Svg.Path() + .move(1, 2) + .line(3, 4) + .curve(5, 6, 7, 8, 9, 10) + .translate(10, 100); + + expect(path.pathElements).toEqual([ + { command: 'M', x: 11, y: 102 }, + { command: 'L', x: 13, y: 104 }, + { command: 'C', x1: 15, y1: 106, x2: 17, y2: 108, x: 19, y: 110 } + ]); + }); + + it('should transform path correctly with custom function', function () { + var path = new Chartist.Svg.Path() + .move(1, 2) + .line(3, 4) + .curve(5, 6, 7, 8, 9, 10) + .transform(function(element, paramName, elementIndex, paramIndex) { + if(paramIndex > 3) { + return 0; + } else if(paramName[0] === 'y') { + return 100; + } + }); + + expect(path.pathElements).toEqual([ + { command: 'M', x: 1, y: 100 }, + { command: 'L', x: 3, y: 100 }, + { command: 'C', x1: 5, y1: 100, x2: 7, y2: 100, x: 0, y: 0 } + ]); + }); + }); }); From 3cd52116d9347d6727bc2ab310e25f6fc4cf4282 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 1 Feb 2015 03:07:10 +0100 Subject: [PATCH 171/593] Fixed some JSDoc comment issues --- src/scripts/charts/pie.js | 2 +- src/scripts/class.js | 4 ++-- src/scripts/core.js | 16 ++++++++-------- src/scripts/svg.js | 37 ++++++++++++++++++------------------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index e1184355..b4d210c1 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -53,7 +53,7 @@ * @param center * @param label * @param direction - * @returns {string} + * @return {string} */ function determineAnchorPosition(center, label, direction) { var toTheRight = label.x > center.x; diff --git a/src/scripts/class.js b/src/scripts/class.js index 10c0c603..9aa97c24 100644 --- a/src/scripts/class.js +++ b/src/scripts/class.js @@ -23,7 +23,7 @@ * @memberof Chartist.Class * @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. * @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. - * @returns {Function} Constructor function of the new class + * @return {Function} Constructor function of the new class * * @example * var Fruit = Class.extend({ @@ -91,7 +91,7 @@ * @memberof Chartist.Class * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. * @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. - * @returns {Function} Constructor function of the newly created mixin class + * @return {Function} Constructor function of the newly created mixin class * * @example * var Fruit = Class.extend({ diff --git a/src/scripts/core.js b/src/scripts/core.js index b20d6876..98ff13bd 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -65,7 +65,7 @@ var Chartist = { * @param {String} str * @param {String} subStr * @param {String} newSubStr - * @returns {String} + * @return {String} */ Chartist.replaceAll = function(str, subStr, newSubStr) { return str.replace(new RegExp(subStr, 'g'), newSubStr); @@ -76,7 +76,7 @@ var Chartist = { * * @memberof Chartist.Core * @param {String|Number} value - * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel + * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel */ Chartist.stripUnit = function(value) { if(typeof value === 'string') { @@ -92,7 +92,7 @@ var Chartist = { * @memberof Chartist.Core * @param {Number} value * @param {String} unit - * @returns {String} Returns the passed number value with unit. + * @return {String} Returns the passed number value with unit. */ Chartist.ensureUnit = function(value, unit) { if(typeof value === 'number') { @@ -118,7 +118,7 @@ var Chartist = { * * @memberof Chartist.Core * @param length - * @returns {Array} + * @return {Array} */ Chartist.times = function(length) { return Array.apply(null, new Array(length)); @@ -130,7 +130,7 @@ var Chartist = { * @memberof Chartist.Core * @param previous * @param current - * @returns {*} + * @return {*} */ Chartist.sum = function(previous, current) { return previous + current; @@ -142,7 +142,7 @@ var Chartist = { * @memberof Chartist.Core * @param arr * @param cb - * @returns {Array} + * @return {Array} */ Chartist.serialMap = function(arr, cb) { var result = [], @@ -181,7 +181,7 @@ var Chartist = { * * @memberof Chartist.Core * @param {Number|String|Object} data - * @returns {String} + * @return {String} */ Chartist.serialize = function(data) { if(data === null || data === undefined) { @@ -202,7 +202,7 @@ var Chartist = { * * @memberof Chartist.Core * @param {String} data - * @returns {String|Number|Object} + * @return {String|Number|Object} */ Chartist.deserialize = function(data) { if(typeof data !== 'string') { diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 2f3c556b..1a4796f2 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -64,7 +64,7 @@ * @memberof Chartist.Svg * @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. * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {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. + * @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. */ function attr(attributes, ns) { if(typeof attributes === 'string') { @@ -99,7 +99,7 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @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 - * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ function elem(name, attributes, className, insertFirst) { return new Chartist.Svg(name, attributes, className, this, insertFirst); @@ -108,7 +108,7 @@ /** * Returns the parent Chartist.SVG wrapper object * - * @returns {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. + * @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. */ function parent() { return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; @@ -117,7 +117,7 @@ /** * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. * - * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element + * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element */ function root() { var node = this._node; @@ -131,7 +131,7 @@ * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. * * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found + * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found */ function querySelector(selector) { var foundNode = this._node.querySelector(selector); @@ -142,7 +142,7 @@ * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. * * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found + * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found */ function querySelectorAll(selector) { var foundNodes = this._node.querySelectorAll(selector); @@ -157,7 +157,7 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element + * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element */ function foreignObject(content, attributes, className, insertFirst) { // If content is string then we convert it to DOM @@ -186,7 +186,7 @@ * * @memberof Chartist.Svg * @param {String} t The text that should be added to the text element that is created - * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element + * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element */ function text(t) { this._node.appendChild(document.createTextNode(t)); @@ -197,7 +197,7 @@ * This method will clear all child nodes of the current wrapper object. * * @memberof Chartist.Svg - * @returns {Chartist.Svg} The same wrapper object that got emptied + * @return {Chartist.Svg} The same wrapper object that got emptied */ function empty() { while (this._node.firstChild) { @@ -211,7 +211,7 @@ * 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. * * @memberof Chartist.Svg - * @returns {Chartist.Svg} The parent wrapper object of the element that got removed + * @return {Chartist.Svg} The parent wrapper object of the element that got removed */ function remove() { this._node.parentNode.removeChild(this._node); @@ -223,7 +223,7 @@ * * @memberof Chartist.Svg * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object - * @returns {Chartist.Svg} The wrapper of the new element + * @return {Chartist.Svg} The wrapper of the new element */ function replace(newElement) { this._node.parentNode.replaceChild(newElement._node, this._node); @@ -236,7 +236,7 @@ * @memberof Chartist.Svg * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Chartist.Svg} The wrapper of the appended object + * @return {Chartist.Svg} The wrapper of the appended object */ function append(element, insertFirst) { if(insertFirst && this._node.firstChild) { @@ -252,7 +252,7 @@ * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. * * @memberof Chartist.Svg - * @returns {Array} A list of classes or an empty array if there are no classes on the current element + * @return {Array} A list of classes or an empty array if there are no classes on the current element */ function classes() { return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; @@ -263,7 +263,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element + * @return {Chartist.Svg} The wrapper of the current element */ function addClass(names) { this._node.setAttribute('class', @@ -282,7 +282,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element + * @return {Chartist.Svg} The wrapper of the current element */ function removeClass(names) { var removedClasses = names.trim().split(/\s+/); @@ -298,7 +298,7 @@ * Removes all classes from the current element. * * @memberof Chartist.Svg - * @returns {Chartist.Svg} The wrapper of the current element + * @return {Chartist.Svg} The wrapper of the current element */ function removeAllClasses() { this._node.setAttribute('class', ''); @@ -367,7 +367,7 @@ * @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. * @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. * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. - * @returns {Chartist.Svg} The current element where the animation was added + * @return {Chartist.Svg} The current element where the animation was added */ function animate(animations, guided, eventEmitter) { if(guided === undefined) { @@ -508,7 +508,7 @@ * * @memberof Chartist.Svg * @param {String} feature The SVG 1.1 feature that should be checked for support. - * @returns {Boolean} True of false if the feature is supported or not + * @return {Boolean} True of false if the feature is supported or not */ Chartist.Svg.isSupported = function(feature) { return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); @@ -589,5 +589,4 @@ Chartist.Svg.List = Chartist.Class.extend({ constructor: SvgList }); - }(window, document, Chartist)); From a1a36af7ffd7923c0fbaba5088f4925ec26a8c81 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 1 Feb 2015 03:15:53 +0100 Subject: [PATCH 172/593] Version bump to 0.7.0 --- CHANGELOG.md | 9 + bower.json | 2 +- dist/chartist.js | 1107 ++++++++++++++++++++++++++------------ dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- src/scripts/core.js | 2 +- 8 files changed, 769 insertions(+), 361 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcb54269..4ebcaf14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +v0.7.0 - 01 Feb 2015 +-------------------- +- This version introduces a new option in the bar charts to draw them horizontally +- Underlying changes for axis model that allows flexible value projection and removes code duplication +- Added SVG Path API for manipulating SVG paths. This can be used in animations or to transform the output by Chartist further. +- The fullWidth and centerBars options were removed from the bar chart +- Updating chart after options update enables the use of 'print' media query in responsive options to have a quick redraw before printing. This only works in Chrome 40 so far +- Fixed issues with 0 values in series object data notation + v0.6.1 - 23 Jan 2015 -------------------- - Fixed bug that prevented data events to be captured diff --git a/bower.json b/bower.json index 8749ce3a..ced938ae 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.6.1", + "version": "0.7.0", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index f452a56c..195e948d 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { - /* Chartist.js 0.6.1 + /* Chartist.js 0.7.0 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.6.1' + version: '0.7.0' }; (function (window, document, Chartist) { @@ -86,7 +86,7 @@ * @param {String} str * @param {String} subStr * @param {String} newSubStr - * @returns {String} + * @return {String} */ Chartist.replaceAll = function(str, subStr, newSubStr) { return str.replace(new RegExp(subStr, 'g'), newSubStr); @@ -97,7 +97,7 @@ * * @memberof Chartist.Core * @param {String|Number} value - * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel + * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel */ Chartist.stripUnit = function(value) { if(typeof value === 'string') { @@ -113,7 +113,7 @@ * @memberof Chartist.Core * @param {Number} value * @param {String} unit - * @returns {String} Returns the passed number value with unit. + * @return {String} Returns the passed number value with unit. */ Chartist.ensureUnit = function(value, unit) { if(typeof value === 'number') { @@ -139,7 +139,7 @@ * * @memberof Chartist.Core * @param length - * @returns {Array} + * @return {Array} */ Chartist.times = function(length) { return Array.apply(null, new Array(length)); @@ -151,7 +151,7 @@ * @memberof Chartist.Core * @param previous * @param current - * @returns {*} + * @return {*} */ Chartist.sum = function(previous, current) { return previous + current; @@ -163,7 +163,7 @@ * @memberof Chartist.Core * @param arr * @param cb - * @returns {Array} + * @return {Array} */ Chartist.serialMap = function(arr, cb) { var result = [], @@ -202,7 +202,7 @@ * * @memberof Chartist.Core * @param {Number|String|Object} data - * @returns {String} + * @return {String} */ Chartist.serialize = function(data) { if(data === null || data === undefined) { @@ -223,7 +223,7 @@ * * @memberof Chartist.Core * @param {String} data - * @returns {String|Number|Object} + * @return {String|Number|Object} */ Chartist.deserialize = function(data) { if(typeof data !== 'string') { @@ -280,18 +280,46 @@ return svg; }; + + /** + * Reverses the series, labels and series data arrays. + * + * @memberof Chartist.Core + * @param data + */ + Chartist.reverseData = function(data) { + data.labels.reverse(); + data.series.reverse(); + for (var i = 0; i < data.series.length; i++) { + if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { + data.series[i].data.reverse(); + } else { + data.series[i].reverse(); + } + } + }; + /** * Convert data series into plain array * * @memberof Chartist.Core * @param {Object} data The series object that contains the data to be visualized in the chart + * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ - Chartist.getDataArray = function (data) { + Chartist.getDataArray = function (data, reverse) { var array = [], value, localData; + // If the data should be reversed but isn't we need to reverse it + // If it's reversed but it shouldn't we need to reverse it back + // That's required to handle data updates correctly and to reflect the responsive configurations + if(reverse && !data.reversed || !reverse && data.reversed) { + Chartist.reverseData(data); + data.reversed = !data.reversed; + } + for (var i = 0; i < data.series.length; i++) { // If the series array contains an object with a data property we will use the property // otherwise the value directly (array or number). @@ -304,11 +332,10 @@ array[i] = localData; } - // Convert object values to numbers for (var j = 0; j < array[i].length; j++) { value = array[i][j]; - value = value.value || value; + value = value.value === 0 ? 0 : (value.value || value); array[i][j] = +value; } } @@ -338,6 +365,11 @@ return dataArray; }; + Chartist.getMetaData = function(series, index) { + var value = series.data ? series.data[index] : series[index]; + return value ? Chartist.serialize(value.meta) : undefined; + }; + /** * Calculate the order of magnitude for the chart scale * @@ -353,15 +385,13 @@ * Project a data length into screen coordinates (pixels) * * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart + * @param {Object} axisLength The svg element for the chart * @param {Number} length Single data value from a series array * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} options The Object that contains all the optional values for the chart * @return {Number} The projected data length in pixels */ - Chartist.projectLength = function (svg, length, bounds, options) { - var availableHeight = Chartist.getAvailableHeight(svg, options); - return (length / bounds.range * availableHeight); + Chartist.projectLength = function (axisLength, length, bounds) { + return length / bounds.range * axisLength; }; /** @@ -410,13 +440,13 @@ * Calculate and retrieve all the bounds for the chart and return them in one array * * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart + * @param {Number} axisLength The length of the Axis used for * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. - * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} scaleMinSpace The minimum projected length a step should result in * @param {Number} referenceValue The reference value for the chart. * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (svg, highLow, options, referenceValue) { + Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) { var i, newMin, newMax, @@ -425,10 +455,6 @@ low: highLow.low }; - // Overrides of high / low from settings - bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high); - bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low); - // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity if(bounds.high === bounds.low) { @@ -462,13 +488,13 @@ // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace // If we are already below the scaleMinSpace value we will scale up - var length = Chartist.projectLength(svg, bounds.step, bounds, options), - scaleUp = length < options.axisY.scaleMinSpace; + var length = Chartist.projectLength(axisLength, bounds.step, bounds), + scaleUp = length < scaleMinSpace; while (true) { - if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) { + if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { bounds.step *= 2; - } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) { + } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { bounds.step /= 2; } else { break; @@ -527,13 +553,15 @@ * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ Chartist.createChartRect = function (svg, options) { - var yOffset = options.axisY ? options.axisY.offset : 0, - xOffset = options.axisX ? options.axisX.offset : 0; + var yOffset = options.axisY ? options.axisY.offset || 0 : 0, + xOffset = options.axisX ? options.axisX.offset || 0 : 0, + w = Chartist.stripUnit(options.width) || svg.width(), + h = Chartist.stripUnit(options.height) || svg.height(); return { x1: options.chartPadding + yOffset, - y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset), + y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding), + x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset), y2: options.chartPadding, width: function () { return this.x2 - this.x1; @@ -545,207 +573,121 @@ }; /** - * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element. + * Creates a grid line based on a projected value. * - * @param {Object} parent The SVG element where the label should be created as a child - * @param {String} text The label text - * @param {Object} attributes An object with all attributes that should be set on the label element - * @param {String} className The class names that should be set for this element - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - * @returns {Object} The newly created SVG element - */ - Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) { - if(supportsForeignObject) { - var content = '' + text + ''; - return parent.foreignObject(content, attributes); - } else { - return parent.elem('text', attributes, className).text(text); - } + * @memberof Chartist.Core + * @param projectedValue + * @param index + * @param axis + * @param offset + * @param length + * @param group + * @param classes + * @param eventEmitter + */ + Chartist.createGrid = function(projectedValue, index, axis, offset, length, group, classes, eventEmitter) { + var positionalData = {}; + positionalData[axis.units.pos + '1'] = projectedValue.pos; + positionalData[axis.units.pos + '2'] = projectedValue.pos; + positionalData[axis.counterUnits.pos + '1'] = offset; + positionalData[axis.counterUnits.pos + '2'] = offset + length; + + var gridElement = group.elem('line', positionalData, classes.join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', + Chartist.extend({ + type: 'grid', + axis: axis.units.pos, + index: index, + group: group, + element: gridElement + }, positionalData) + ); }; /** - * Generate grid lines and labels for the x-axis into grid and labels group SVG elements + * Creates a label based on a projected value and an axis. * * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} data The Object that contains the data to be visualized in the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create X-Axis - data.labels.forEach(function (value, index) { - var interpolatedValue = options.axisX.labelInterpolationFnc(value, index), - width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)), - height = options.axisX.offset, - pos = chartRect.x1 + width * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { - return; - } - - if (options.axisX.showGrid) { - var gridElement = grid.elem('line', { - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }, [options.classNames.grid, options.classNames.horizontal].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'x', - index: index, - group: grid, - element: gridElement, - x1: pos, - y1: chartRect.y1, - x2: pos, - y2: chartRect.y2 - }); - } - - if (options.axisX.showLabel) { - var labelPosition = { - x: pos + options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject); + * @param projectedValue + * @param index + * @param labels + * @param axis + * @param axisOffset + * @param labelOffset + * @param group + * @param classes + * @param useForeignObject + * @param eventEmitter + */ + Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + var labelElement, + positionalData = {}; + positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; + positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; + positionalData[axis.units.len] = projectedValue.len; + positionalData[axis.counterUnits.len] = axisOffset; + + if(useForeignObject) { + var content = '' + labels[index] + ''; + labelElement = group.foreignObject(content, Chartist.extend({ + style: 'overflow: visible;' + }, positionalData)); + } else { + labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]); + } - eventEmitter.emit('draw', { - type: 'label', - axis: 'x', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.width; - } - }); - } - }); + eventEmitter.emit('draw', Chartist.extend({ + type: 'label', + axis: axis, + index: index, + group: group, + element: labelElement, + text: labels[index] + }, positionalData)); }; /** - * Generate grid lines and labels for the y-axis into grid and labels group SVG elements + * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect. * * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart - * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines - * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element - */ - Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) { - // Create Y-Axis - bounds.values.forEach(function (value, index) { - var interpolatedValue = options.axisY.labelInterpolationFnc(value, index), - width = options.axisY.offset, - height = chartRect.height() / bounds.values.length, - pos = chartRect.y1 - height * index; - - // If interpolated value returns falsey (except 0) we don't draw the grid line - if (!interpolatedValue && interpolatedValue !== 0) { + * @param axis + * @param data + * @param chartRect + * @param gridGroup + * @param labelGroup + * @param useForeignObject + * @param options + * @param eventEmitter + */ + Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { + var axisOptions = options['axis' + axis.units.pos.toUpperCase()], + projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform), + labelValues = data.map(axisOptions.labelInterpolationFnc); + + projectedValues.forEach(function(projectedValue, index) { + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + if(!labelValues[index] && labelValues[index] !== 0) { return; } - if (options.axisY.showGrid) { - var gridElement = grid.elem('line', { - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }, [options.classNames.grid, options.classNames.vertical].join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', { - type: 'grid', - axis: 'y', - index: index, - group: grid, - element: gridElement, - x1: chartRect.x1, - y1: pos, - x2: chartRect.x2, - y2: pos - }); + if(axisOptions.showGrid) { + Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ + options.classNames.grid, + options.classNames[axis.units.dir] + ], eventEmitter); } - if (options.axisY.showLabel) { - var labelPosition = { - x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0), - y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0) - }; - - var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, { - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - style: 'overflow: visible;' - }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject); - - eventEmitter.emit('draw', { - type: 'label', - axis: 'y', - index: index, - group: labels, - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y, - width: width, - height: height, - // TODO: Remove in next major release - get space() { - window.console.warn('EventEmitter: space is deprecated, use width or height instead.'); - return this.height; - } - }); + if(axisOptions.showLabel) { + Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [ + options.classNames.label, + options.classNames[axis.units.dir] + ], useForeignObject, eventEmitter); } }); }; - /** - * Determine the current point on the svg element to draw the data series - * - * @memberof Chartist.Core - * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element - * @param {Object} bounds All the values to set the bounds of the chart - * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Number} index The index of the current project point - * @param {Object} options The chart options that are used to influence the calculations - * @return {Object} The coordinates object of the current project point containing an x and y number property - */ - Chartist.projectPoint = function (chartRect, bounds, data, index, options) { - return { - x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index, - y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step) - }; - }; - - // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one /** * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches * @@ -954,7 +896,7 @@ * @memberof Chartist.Class * @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. * @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. - * @returns {Function} Constructor function of the new class + * @return {Function} Constructor function of the new class * * @example * var Fruit = Class.extend({ @@ -1022,7 +964,7 @@ * @memberof Chartist.Class * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. * @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. - * @returns {Function} Constructor function of the newly created mixin class + * @return {Function} Constructor function of the newly created mixin class * * @example * var Fruit = Class.extend({ @@ -1240,6 +1182,10 @@ // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + // Register options change listener that will trigger a chart update + this.eventEmitter.addEventHandler('optionsChanged', function() { + this.update(); + }.bind(this)); // Before the first chart creation we need to register us with all plugins that are configured // Initialize all relevant plugins with our chart object and the plugin options specified in the config @@ -1394,7 +1340,7 @@ * @memberof Chartist.Svg * @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. * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @returns {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. + * @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. */ function attr(attributes, ns) { if(typeof attributes === 'string') { @@ -1429,7 +1375,7 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @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 - * @returns {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ function elem(name, attributes, className, insertFirst) { return new Chartist.Svg(name, attributes, className, this, insertFirst); @@ -1438,7 +1384,7 @@ /** * Returns the parent Chartist.SVG wrapper object * - * @returns {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. + * @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. */ function parent() { return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; @@ -1447,7 +1393,7 @@ /** * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. * - * @returns {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element + * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element */ function root() { var node = this._node; @@ -1461,7 +1407,7 @@ * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. * * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg} The SVG wrapper for the element found or null if no element was found + * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found */ function querySelector(selector) { var foundNode = this._node.querySelector(selector); @@ -1472,7 +1418,7 @@ * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. * * @param {String} selector A CSS selector that is used to query for child SVG elements - * @returns {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found + * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found */ function querySelectorAll(selector) { var foundNodes = this._node.querySelectorAll(selector); @@ -1487,7 +1433,7 @@ * @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. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @returns {Chartist.Svg} New wrapper object that wraps the foreignObject element + * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element */ function foreignObject(content, attributes, className, insertFirst) { // If content is string then we convert it to DOM @@ -1516,7 +1462,7 @@ * * @memberof Chartist.Svg * @param {String} t The text that should be added to the text element that is created - * @returns {Chartist.Svg} The same wrapper object that was used to add the newly created element + * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element */ function text(t) { this._node.appendChild(document.createTextNode(t)); @@ -1527,7 +1473,7 @@ * This method will clear all child nodes of the current wrapper object. * * @memberof Chartist.Svg - * @returns {Chartist.Svg} The same wrapper object that got emptied + * @return {Chartist.Svg} The same wrapper object that got emptied */ function empty() { while (this._node.firstChild) { @@ -1541,7 +1487,7 @@ * 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. * * @memberof Chartist.Svg - * @returns {Chartist.Svg} The parent wrapper object of the element that got removed + * @return {Chartist.Svg} The parent wrapper object of the element that got removed */ function remove() { this._node.parentNode.removeChild(this._node); @@ -1553,7 +1499,7 @@ * * @memberof Chartist.Svg * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object - * @returns {Chartist.Svg} The wrapper of the new element + * @return {Chartist.Svg} The wrapper of the new element */ function replace(newElement) { this._node.parentNode.replaceChild(newElement._node, this._node); @@ -1566,7 +1512,7 @@ * @memberof Chartist.Svg * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @returns {Chartist.Svg} The wrapper of the appended object + * @return {Chartist.Svg} The wrapper of the appended object */ function append(element, insertFirst) { if(insertFirst && this._node.firstChild) { @@ -1582,7 +1528,7 @@ * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. * * @memberof Chartist.Svg - * @returns {Array} A list of classes or an empty array if there are no classes on the current element + * @return {Array} A list of classes or an empty array if there are no classes on the current element */ function classes() { return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; @@ -1593,7 +1539,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element + * @return {Chartist.Svg} The wrapper of the current element */ function addClass(names) { this._node.setAttribute('class', @@ -1612,7 +1558,7 @@ * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names - * @returns {Chartist.Svg} The wrapper of the current element + * @return {Chartist.Svg} The wrapper of the current element */ function removeClass(names) { var removedClasses = names.trim().split(/\s+/); @@ -1628,7 +1574,7 @@ * Removes all classes from the current element. * * @memberof Chartist.Svg - * @returns {Chartist.Svg} The wrapper of the current element + * @return {Chartist.Svg} The wrapper of the current element */ function removeAllClasses() { this._node.setAttribute('class', ''); @@ -1697,7 +1643,7 @@ * @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. * @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. * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. - * @returns {Chartist.Svg} The current element where the animation was added + * @return {Chartist.Svg} The current element where the animation was added */ function animate(animations, guided, eventEmitter) { if(guided === undefined) { @@ -1838,7 +1784,7 @@ * * @memberof Chartist.Svg * @param {String} feature The SVG 1.1 feature that should be checked for support. - * @returns {Boolean} True of false if the feature is supported or not + * @return {Boolean} True of false if the feature is supported or not */ Chartist.Svg.isSupported = function(feature) { return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); @@ -1919,7 +1865,309 @@ Chartist.Svg.List = Chartist.Class.extend({ constructor: SvgList }); + }(window, document, Chartist)); + ;/** + * Chartist SVG path module for SVG path description creation and modification. + * + * @module Chartist.Svg.Path + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + /** + * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported. + * + * @memberof Chartist.Svg.Path + * @type {Object} + */ + var elementDescriptions = { + m: ['x', 'y'], + l: ['x', 'y'], + c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'] + }; + + /** + * Default options for newly created SVG path objects. + * + * @memberof Chartist.Svg.Path + * @type {Object} + */ + var defaultOptions = { + // 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. + accuracy: 3 + }; + + function element(command, params, pathElements, pos, relative) { + pathElements.splice(pos, 0, Chartist.extend({ + command: relative ? command.toLowerCase() : command.toUpperCase() + }, params)); + } + + function forEachParam(pathElements, cb) { + pathElements.forEach(function(pathElement, pathElementIndex) { + elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) { + cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + }); + }); + } + + /** + * Used to construct a new path object. + * + * @memberof Chartist.Svg.Path + * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end) + * @param {Object} options Options object that overrides the default objects. See default options for more details. + * @constructor + */ + function SvgPath(close, options) { + this.pathElements = []; + this.pos = 0; + this.close = close; + this.options = Chartist.extend({}, defaultOptions, options); + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} [position] If a number is passed then the cursor is set to this position in the path element array. + * @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. + */ + function position(pos) { + if(pos !== undefined) { + this.pos = Math.max(0, Math.min(this.pathElements.length, pos)); + return this; + } else { + return this.pos; + } + } + + /** + * Removes elements from the path starting at the current position. + * + * @memberof Chartist.Svg.Path + * @param {Number} count Number of path elements that should be removed from the current position. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function remove(count) { + this.pathElements.splice(this.pos, count); + return this; + } + + /** + * Use this function to add a new move SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The x coordinate for the move element. + * @param {Number} y The y coordinate for the move element. + * @param {Boolean} relative If set to true the move element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function move(x, y, relative) { + element('M', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * Use this function to add a new line SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The x coordinate for the line element. + * @param {Number} y The y coordinate for the line element. + * @param {Boolean} relative If set to true the line element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function line(x, y, relative) { + element('L', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * Use this function to add a new curve SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x1 The x coordinate for the first control point of the bezier curve. + * @param {Number} y1 The y coordinate for the first control point of the bezier curve. + * @param {Number} x2 The x coordinate for the second control point of the bezier curve. + * @param {Number} y2 The y coordinate for the second control point of the bezier curve. + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} relative If set to true the curve element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function curve(x1, y1, x2, y2, x, y, relative) { + element('C', { + x1: +x1, + y1: +y1, + x2: +x2, + y2: +y2, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function parse(path) { + // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] + var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') + .replace(/([0-9])([A-Za-z])/g, '$1 $2') + .split(/[\s,]+/) + .reduce(function(result, element) { + if(element.match(/[A-Za-z]/)) { + result.push([]); + } + + result[result.length - 1].push(element); + return result; + }, []); + + // If this is a closed path we remove the Z at the end because this is determined by the close option + if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') { + chunks.pop(); + } + + // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters + // For example {command: 'M', x: '10', y: '10'} + var elements = chunks.map(function(chunk) { + var command = chunk.shift(), + description = elementDescriptions[command.toLowerCase()]; + + return Chartist.extend({ + command: command + }, description.reduce(function(result, paramName, index) { + result[paramName] = +chunk[index]; + return result; + }, {})); + }); + + // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position + var spliceArgs = [this.pos, 0]; + Array.prototype.push.apply(spliceArgs, elements); + Array.prototype.splice.apply(this.pathElements, spliceArgs); + // Increase the internal position by the element count + this.pos += elements.length; + + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @return {String} + */ + function stringify() { + var accuracyMultiplier = Math.pow(10, this.options.accuracy); + + return this.pathElements.reduce(function(path, pathElement) { + var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) { + return this.options.accuracy ? + (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) : + pathElement[paramName]; + }.bind(this)); + + return path + pathElement.command + params.join(','); + }.bind(this), '') + (this.close ? 'Z' : ''); + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function scale(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] *= paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function translate(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] += paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * The method signature of the callback function looks like this: + * ```javascript + * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) + * ``` + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function transform(transformFnc) { + forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) { + var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + if(transformed || transformed === 0) { + pathElement[paramName] = transformed; + } + }); + return this; + } + + /** + * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. + * + * @memberof Chartist.Svg.Path + * @return {Chartist.Svg.Path} + */ + function clone() { + var c = new Chartist.Svg.Path(this.close); + c.pos = this.pos; + c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { + return Chartist.extend({}, pathElement); + }); + c.options = Chartist.extend({}, this.options); + return c; + } + + Chartist.Svg.Path = Chartist.Class.extend({ + constructor: SvgPath, + position: position, + remove: remove, + move: move, + line: line, + curve: curve, + scale: scale, + translate: translate, + transform: transform, + parse: parse, + stringify: stringify, + clone: clone + }); + Chartist.Svg.Path.elementDescriptions = elementDescriptions; }(window, document, Chartist)); ;/** * 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. @@ -1994,6 +2242,8 @@ chartPadding: 5, // 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. fullWidth: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-line', @@ -2016,105 +2266,159 @@ */ function createChart(options) { var seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length); + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - // initialize bounds - bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options); - var chartRect = Chartist.createChartRect(this.svg, options); + + var highLow = Chartist.getHighLow(normalizedData); + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); + + var axisX = new Chartist.StepAxis( + Chartist.Axis.units.x, + chartRect, + function xAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { + stepCount: this.data.labels.length, + stretch: options.fullWidth + } + ); + + var axisY = new Chartist.LinearScaleAxis( + Chartist.Axis.units.y, + chartRect, + function yAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) + }, + { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace + } + ); + // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), + gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createAxis( + axisX, + this.data.labels, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + Chartist.createAxis( + axisY, + axisY.bounds.values, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - seriesGroups[i] = this.svg.elem('g'); + this.data.series.forEach(function(series, seriesIndex) { + seriesGroups[seriesIndex] = this.svg.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) + seriesGroups[seriesIndex].attr({ + 'series-name': series.name, + 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ + seriesGroups[seriesIndex].addClass([ options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - var p, - pathCoordinates = [], - point; + var pathCoordinates = []; - for (var j = 0; j < normalizedData[i].length; j++) { - p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options); + normalizedData[seriesIndex].forEach(function(value, valueIndex) { + var p = { + x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + }; pathCoordinates.push(p.x, p.y); //If we should show points we need to create them now to avoid secondary loop // Small offset for Firefox to render squares correctly if (options.showPoint) { - point = seriesGroups[i].elem('line', { + var point = seriesGroups[seriesIndex].elem('line', { x1: p.x, y1: p.y, x2: p.x + 0.01, y2: p.y }, options.classNames.point).attr({ - 'value': normalizedData[i][j], - 'meta': this.data.series[i].data ? - Chartist.serialize(this.data.series[i].data[j].meta) : - Chartist.serialize(this.data.series[i][j].meta) + 'value': value, + 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'point', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], + value: value, + index: valueIndex, + group: seriesGroups[seriesIndex], element: point, x: p.x, y: p.y }); } - } + }.bind(this)); // TODO: Nicer handling of conditions, maybe composition? if (options.showLine || options.showArea) { - // TODO: We should add a path API in the SVG library for easier path creation - var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]]; + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); // If smoothed path and path has more than two points then use catmull rom to bezier algorithm if (options.lineSmooth && pathCoordinates.length > 4) { var cr = Chartist.catmullRom2bezier(pathCoordinates); for(var k = 0; k < cr.length; k++) { - pathElements.push('C' + cr[k].join()); + Chartist.Svg.Path.prototype.curve.apply(path, cr[k]); } } else { for(var l = 3; l < pathCoordinates.length; l += 2) { - pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]); + path.line(pathCoordinates[l - 1], pathCoordinates[l]); } } if(options.showLine) { - var line = seriesGroups[i].elem('path', { - d: pathElements.join('') + var line = seriesGroups[seriesIndex].elem('path', { + d: path.stringify() }, options.classNames.line, true).attr({ - 'values': normalizedData[i] + 'values': normalizedData[seriesIndex] }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'line', - values: normalizedData[i], - index: i, - group: seriesGroups[i], + values: normalizedData[seriesIndex], + path: path.clone(), + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], element: line }); } @@ -2122,38 +2426,43 @@ if(options.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, bounds.max), bounds.min); - - // If we need to draw area shapes we just make a copy of our pathElements SVG path array - var areaPathElements = pathElements.slice(); + var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); // We project the areaBase value into screen coordinates - var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options); - // And splice our new area path array to add the missing path elements to close the area shape - areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y); - areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1]; - areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y); + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; + + // Clone original path and splice our new area path to add the missing path elements to close the area shape + var areaPath = path.clone(); + // Modify line path and add missing elements for area + areaPath.position(0) + .remove(1) + .move(chartRect.x1, areaBaseProjected) + .line(pathCoordinates[0], pathCoordinates[1]) + .position(areaPath.pathElements.length) + .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); // Create the new path for the area shape with the area class from the options - var area = seriesGroups[i].elem('path', { - d: areaPathElements.join('') + var area = seriesGroups[seriesIndex].elem('path', { + d: areaPath.stringify() }, options.classNames.area, true).attr({ - 'values': normalizedData[i] + 'values': normalizedData[seriesIndex] }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'area', - values: normalizedData[i], - index: i, - group: seriesGroups[i], + values: normalizedData[seriesIndex], + path: areaPath.clone(), + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], element: area }); } } - } + }.bind(this)); this.eventEmitter.emit('created', { - bounds: bounds, + bounds: axisY.bounds, chartRect: chartRect, svg: this.svg, options: options @@ -2271,7 +2580,9 @@ // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop + labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum width in pixel of the scale steps + scaleMinSpace: 40 }, // Options for Y-Axis axisY: { @@ -2303,12 +2614,12 @@ chartPadding: 5, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, - // 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. For bar charts this might be used in conjunction with the centerBars property set to false. - fullWidth: false, - // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property. - centerBars: true, // If set to true this property will cause the series bars to be stacked and 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. stackBars: false, + // 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. + horizontalBars: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', @@ -2329,8 +2640,7 @@ */ function createChart(options) { var seriesGroups = [], - bounds, - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length), + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), highLow; // Create new svg element @@ -2346,92 +2656,179 @@ } else { highLow = Chartist.getHighLow(normalizedData); } - - // initialize bounds - bounds = Chartist.getBounds(this.svg, highLow, options, 0); + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); var chartRect = Chartist.createChartRect(this.svg, options); + + var valueAxis, + labelAxis; + + if(options.horizontalBars) { + labelAxis = new Chartist.StepAxis( + Chartist.Axis.units.y, + chartRect, + function timeAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length + }, + { + stepCount: this.data.labels.length, + stretch: options.fullHeight + } + ); + + valueAxis = new Chartist.LinearScaleAxis( + Chartist.Axis.units.x, + chartRect, + function valueAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { + highLow: highLow, + scaleMinSpace: options.axisX.scaleMinSpace, + referenceValue: 0 + } + ); + } else { + labelAxis = new Chartist.StepAxis( + Chartist.Axis.units.x, + chartRect, + function timeAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { + stepCount: this.data.labels.length + } + ); + + valueAxis = new Chartist.LinearScaleAxis( + Chartist.Axis.units.y, + chartRect, + function valueAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) + }, + { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace, + referenceValue: 0 + } + ); + } + // Start drawing - var labels = this.svg.elem('g').addClass(options.classNames.labelGroup), - grid = this.svg.elem('g').addClass(options.classNames.gridGroup), + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), + gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup), // Projected 0 point - zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options), + zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos), // Used to track the screen coordinates of stacked bars stackedBarValues = []; - Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject); - Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject); + Chartist.createAxis( + labelAxis, + this.data.labels, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + Chartist.createAxis( + valueAxis, + valueAxis.bounds.values, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { + this.data.series.forEach(function(series, seriesIndex) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = i - (this.data.series.length - 1) / 2, + var biPol = seriesIndex - (this.data.series.length - 1) / 2, // Half of the period width between vertical grid lines used to position bars - periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2; + periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2; - seriesGroups[i] = this.svg.elem('g'); + seriesGroups[seriesIndex] = this.svg.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) + seriesGroups[seriesIndex].attr({ + 'series-name': series.name, + 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ + seriesGroups[seriesIndex].addClass([ options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - for(var j = 0; j < normalizedData[i].length; j++) { - var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options), + normalizedData[seriesIndex].forEach(function(value, valueIndex) { + var projected = { + x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + }, bar, - previousStack, - y1, - y2; + previousStack; // Offset to center bar between grid lines - p.x += (options.centerBars ? periodHalfWidth : 0); + projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); // Using bi-polar offset for multiple series if no stacked bars are used - p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance; + projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); // Enter value in stacked bar values used to remember previous screen value for stacking up bars - previousStack = stackedBarValues[j] || zeroPoint.y; - stackedBarValues[j] = previousStack - (zeroPoint.y - p.y); + previousStack = stackedBarValues[valueIndex] || zeroPoint; + stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); + var positions = {}; + positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; + positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - y1 = options.stackBars ? previousStack : zeroPoint.y; - y2 = options.stackBars ? stackedBarValues[j] : p.y; - - bar = seriesGroups[i].elem('line', { - x1: p.x, - y1: y1, - x2: p.x, - y2: y2 - }, options.classNames.bar).attr({ - 'value': normalizedData[i][j], - 'meta': this.data.series[i].data ? - Chartist.serialize(this.data.series[i].data[j].meta) : - Chartist.serialize(this.data.series[i][j].meta) + positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; + + bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({ + 'value': value, + 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); - this.eventEmitter.emit('draw', { + this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', - value: normalizedData[i][j], - index: j, - group: seriesGroups[i], - element: bar, - x1: p.x, - y1: y1, - x2: p.x, - y2: y2 - }); - } - } + value: value, + index: valueIndex, + chartRect: chartRect, + group: seriesGroups[seriesIndex], + element: bar + }, positions)); + }.bind(this)); + }.bind(this)); this.eventEmitter.emit('created', { - bounds: bounds, + bounds: valueAxis.bounds, chartRect: chartRect, svg: this.svg, options: options @@ -2534,7 +2931,9 @@ // An interpolation function for the label value labelInterpolationFnc: Chartist.noop, // 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. - labelDirection: 'neutral' + labelDirection: 'neutral', + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false }; /** @@ -2543,7 +2942,7 @@ * @param center * @param label * @param direction - * @returns {string} + * @return {string} */ function determineAnchorPosition(center, label, direction) { var toTheRight = label.x > center.x; @@ -2571,7 +2970,7 @@ labelRadius, totalDataSum, startAngle = options.startAngle, - dataArray = Chartist.getDataArray(this.data); + dataArray = Chartist.getDataArray(this.data, options.reverseData); // Create SVG.js draw this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 3336c799..4c658a65 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.6.1 +/* Chartist.js 0.7.0 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index b4e8e40c..f3966c60 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.6.1 +/* Chartist.js 0.7.0 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.6.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.getDataArray=function(a){for(var b,c,d=[],e=0;ed;d++)a[c][d]=0;return a},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,d,e){var f=c.getAvailableHeight(a,e);return b/d.range*f},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]=d.axisY.scaleMinSpace))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset:0,e=b.axisX?b.axisX.offset:0;return{x1:b.chartPadding+d,y1:Math.max((c.stripUnit(b.height)||a.height())-b.chartPadding-e,b.chartPadding),x2:Math.max((c.stripUnit(b.width)||a.width())-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createLabel=function(a,b,c,d,e){if(e){var f=''+b+"";return a.foreignObject(f,c)}return a.elem("text",c,d).text(b)},c.createXAxis=function(b,d,e,f,g,h,i){d.labels.forEach(function(j,k){var l=g.axisX.labelInterpolationFnc(j,k),m=b.width()/(d.labels.length-(g.fullWidth?1:0)),n=g.axisX.offset,o=b.x1+m*k;if(l||0===l){if(g.axisX.showGrid){var p=e.elem("line",{x1:o,y1:b.y1,x2:o,y2:b.y2},[g.classNames.grid,g.classNames.horizontal].join(" "));h.emit("draw",{type:"grid",axis:"x",index:k,group:e,element:p,x1:o,y1:b.y1,x2:o,y2:b.y2})}if(g.axisX.showLabel){var q={x:o+g.axisX.labelOffset.x,y:b.y1+g.axisX.labelOffset.y+(i?5:20)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.horizontal].join(" "),i);h.emit("draw",{type:"label",axis:"x",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.width}})}}})},c.createYAxis=function(b,d,e,f,g,h,i){d.values.forEach(function(j,k){var l=g.axisY.labelInterpolationFnc(j,k),m=g.axisY.offset,n=b.height()/d.values.length,o=b.y1-n*k;if(l||0===l){if(g.axisY.showGrid){var p=e.elem("line",{x1:b.x1,y1:o,x2:b.x2,y2:o},[g.classNames.grid,g.classNames.vertical].join(" "));h.emit("draw",{type:"grid",axis:"y",index:k,group:e,element:p,x1:b.x1,y1:o,x2:b.x2,y2:o})}if(g.axisY.showLabel){var q={x:g.chartPadding+g.axisY.labelOffset.x+(i?-10:0),y:o+g.axisY.labelOffset.y+(i?-15:0)},r=c.createLabel(f,""+l,{x:q.x,y:q.y,width:m,height:n,style:"overflow: visible;"},[g.classNames.label,g.classNames.vertical].join(" "),i);h.emit("draw",{type:"label",axis:"y",index:k,group:f,element:r,text:""+l,x:q.x,y:q.y,width:m,height:n,get space(){return a.console.warn("EventEmitter: space is deprecated, use width or height instead."),this.height}})}}})},c.projectPoint=function(a,b,c,d,e){return{x:a.x1+a.width()/(c.length-(c.length>1&&e.fullWidth?1:0))*d,y:a.y1-a.height()*(c[d]-b.min)/(b.range+b.step)}},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var o=c.catmullRom2bezier(l),p=0;pa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral"};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset||0:0,e=b.axisX?b.axisX.offset||0:0,f=c.stripUnit(b.width)||a.width(),g=c.stripUnit(b.height)||a.height();return{x1:b.chartPadding+d,y1:Math.max(g-b.chartPadding-e,b.chartPadding),x2:Math.max(f-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var l=c.catmullRom2bezier(j),m=0;ma.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 2752ad06..0910720f 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","getDataArray","localData","array","i","series","push","j","normalizeDataArray","dataArray","orderOfMagnitude","floor","log","abs","LN10","projectLength","bounds","options","availableHeight","getAvailableHeight","range","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","axisY","scaleMinSpace","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","xOffset","x1","y1","x2","y2","createLabel","parent","text","attributes","supportsForeignObject","content","foreignObject","elem","createXAxis","chartRect","grid","labels","eventEmitter","interpolatedValue","labelInterpolationFnc","fullWidth","pos","showGrid","gridElement","classNames","horizontal","join","emit","type","axis","group","element","showLabel","labelPosition","labelOffset","labelElement","label",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23840,"pos":23835,"col":16,"line":639,"value":"space","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":23840,"pos":23835,"col":16,"line":639,"value":"space","type":"name"},"name":"space"},"space","console","warn","createYAxis","vertical","projectPoint","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","bind","Base","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","classes","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","seriesGroups","normalizedData","chart","labelGroup","gridGroup","series-name","meta","point","pathCoordinates","showPoint","showLine","showArea","pathElements","lineSmooth","cr","k","l","line","areaBase","areaPathElements","areaBaseProjected","area","Line","defaultOptions","stackBars","serialSums","zeroPoint","stackedBarValues","biPol","periodHalfWidth","bar","previousStack","centerBars","seriesBarDistance","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","path","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.6.1\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.6.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 * @returns {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @returns {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * @returns {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 * 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 * @returns {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 * @returns {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + current;\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 * @returns {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 * 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 * @returns {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 * @returns {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.getAttribute(Chartist.xmlNs.qualifiedName);\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 * 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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data) {\n var array = [],\n value,\n localData;\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value || value;\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\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} svg 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 * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (svg, length, bounds, options) {\n var availableHeight = Chartist.getAvailableHeight(svg, options);\n return (length / bounds.range * availableHeight);\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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Object} svg The svg element for the chart\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (svg, highLow, options, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n // Overrides of high / low from settings\n bounds.high = +options.high || (options.high === 0 ? 0 : bounds.high);\n bounds.low = +options.low || (options.low === 0 ? 0 : bounds.low);\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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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(svg, bounds.step, bounds, options),\n scaleUp = length < options.axisY.scaleMinSpace;\n\n while (true) {\n if (scaleUp && Chartist.projectLength(svg, bounds.step, bounds, options) <= options.axisY.scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(svg, bounds.step / 2, bounds, options) >= options.axisY.scaleMinSpace) {\n bounds.step /= 2;\n } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset : 0,\n xOffset = options.axisX ? options.axisX.offset : 0;\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max((Chartist.stripUnit(options.height) || svg.height()) - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max((Chartist.stripUnit(options.width) || svg.width()) - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a label with text and based on support of SVG1.1 extensibility will use a foreignObject with a SPAN element or a fallback to a regular SVG text element.\n *\n * @param {Object} parent The SVG element where the label should be created as a child\n * @param {String} text The label text\n * @param {Object} attributes An object with all attributes that should be set on the label element\n * @param {String} className The class names that should be set for this element\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n * @returns {Object} The newly created SVG element\n */\n Chartist.createLabel = function(parent, text, attributes, className, supportsForeignObject) {\n if(supportsForeignObject) {\n var content = '' + text + '';\n return parent.foreignObject(content, attributes);\n } else {\n return parent.elem('text', attributes, className).text(text);\n }\n };\n\n /**\n * Generate grid lines and labels for the x-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} data The Object that contains the data to be visualized in the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createXAxis = function (chartRect, data, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create X-Axis\n data.labels.forEach(function (value, index) {\n var interpolatedValue = options.axisX.labelInterpolationFnc(value, index),\n width = chartRect.width() / (data.labels.length - (options.fullWidth ? 1 : 0)),\n height = options.axisX.offset,\n pos = chartRect.x1 + width * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisX.showGrid) {\n var gridElement = grid.elem('line', {\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n }, [options.classNames.grid, options.classNames.horizontal].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'x',\n index: index,\n group: grid,\n element: gridElement,\n x1: pos,\n y1: chartRect.y1,\n x2: pos,\n y2: chartRect.y2\n });\n }\n\n if (options.axisX.showLabel) {\n var labelPosition = {\n x: pos + options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (supportsForeignObject ? 5 : 20)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.horizontal].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'x',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.width;\n }\n });\n }\n });\n };\n\n /**\n * Generate grid lines and labels for the y-axis into grid and labels group SVG elements\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Object} grid Chartist.Svg wrapper object to be filled with the grid lines of the chart\n * @param {Object} labels Chartist.Svg wrapper object to be filled with the lables of the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Object} eventEmitter The passed event emitter will be used to emit draw events for labels and gridlines\n * @param {Boolean} supportsForeignObject If this is true then a foreignObject will be used instead of a text element\n */\n Chartist.createYAxis = function (chartRect, bounds, grid, labels, options, eventEmitter, supportsForeignObject) {\n // Create Y-Axis\n bounds.values.forEach(function (value, index) {\n var interpolatedValue = options.axisY.labelInterpolationFnc(value, index),\n width = options.axisY.offset,\n height = chartRect.height() / bounds.values.length,\n pos = chartRect.y1 - height * index;\n\n // If interpolated value returns falsey (except 0) we don't draw the grid line\n if (!interpolatedValue && interpolatedValue !== 0) {\n return;\n }\n\n if (options.axisY.showGrid) {\n var gridElement = grid.elem('line', {\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n }, [options.classNames.grid, options.classNames.vertical].join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw', {\n type: 'grid',\n axis: 'y',\n index: index,\n group: grid,\n element: gridElement,\n x1: chartRect.x1,\n y1: pos,\n x2: chartRect.x2,\n y2: pos\n });\n }\n\n if (options.axisY.showLabel) {\n var labelPosition = {\n x: options.chartPadding + options.axisY.labelOffset.x + (supportsForeignObject ? -10 : 0),\n y: pos + options.axisY.labelOffset.y + (supportsForeignObject ? -15 : 0)\n };\n\n var labelElement = Chartist.createLabel(labels, '' + interpolatedValue, {\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n style: 'overflow: visible;'\n }, [options.classNames.label, options.classNames.vertical].join(' '), supportsForeignObject);\n\n eventEmitter.emit('draw', {\n type: 'label',\n axis: 'y',\n index: index,\n group: labels,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y,\n width: width,\n height: height,\n // TODO: Remove in next major release\n get space() {\n window.console.warn('EventEmitter: space is deprecated, use width or height instead.');\n return this.height;\n }\n });\n }\n });\n };\n\n /**\n * Determine the current point on the svg element to draw the data series\n *\n * @memberof Chartist.Core\n * @param {Object} chartRect The rectangle that sets the bounds for the chart in the svg element\n * @param {Object} bounds All the values to set the bounds of the chart\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Number} index The index of the current project point\n * @param {Object} options The chart options that are used to influence the calculations\n * @return {Object} The coordinates object of the current project point containing an x and y number property\n */\n Chartist.projectPoint = function (chartRect, bounds, data, index, options) {\n return {\n x: chartRect.x1 + chartRect.width() / (data.length - (data.length > 1 && options.fullWidth ? 1 : 0)) * index,\n y: chartRect.y1 - chartRect.height() * (data[index] - bounds.min) / (bounds.range + bounds.step)\n };\n };\n\n // TODO: With multiple media queries the handleMediaChange function is triggered too many times, only need one\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 * @returns {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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @returns {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\n * @returns {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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @returns {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 * @returns {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 * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @returns {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 * 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 * @returns {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', xhtmlNs);\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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 * @returns {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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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 * @returns {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.stripUnit(animationDefinition.begin || 0);\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 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 * @returns {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('www.http://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\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 // 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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, Chartist.getHighLow(normalizedData), options);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var p,\n pathCoordinates = [],\n point;\n\n for (var j = 0; j < normalizedData[i].length; j++) {\n p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options);\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n point = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n // TODO: We should add a path API in the SVG library for easier path creation\n var pathElements = ['M' + pathCoordinates[0] + ',' + pathCoordinates[1]];\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n pathElements.push('C' + cr[k].join());\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n pathElements.push('L' + pathCoordinates[l - 1] + ',' + pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[i].elem('path', {\n d: pathElements.join('')\n }, options.classNames.line, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, bounds.max), bounds.min);\n\n // If we need to draw area shapes we just make a copy of our pathElements SVG path array\n var areaPathElements = pathElements.slice();\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = Chartist.projectPoint(chartRect, bounds, [areaBase], 0, options);\n // And splice our new area path array to add the missing path elements to close the area shape\n areaPathElements.splice(0, 0, 'M' + areaBaseProjected.x + ',' + areaBaseProjected.y);\n areaPathElements[1] = 'L' + pathCoordinates[0] + ',' + pathCoordinates[1];\n areaPathElements.push('L' + pathCoordinates[pathCoordinates.length - 2] + ',' + areaBaseProjected.y);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[i].elem('path', {\n d: areaPathElements.join('')\n }, options.classNames.area, true).attr({\n 'values': normalizedData[i]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[i],\n index: i,\n group: seriesGroups[i],\n element: area\n });\n }\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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 },\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\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. For bar charts this might be used in conjunction with the centerBars property set to false.\n fullWidth: false,\n // This property will cause the bars of the bar chart to be drawn on the grid line rather than between two grid lines. This is useful for single series bar charts and might be used in conjunction with the fullWidth property.\n centerBars: true,\n // If set to true this property will cause the series bars to be stacked and 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 stackBars: 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 label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n bounds,\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\n }\n\n // initialize bounds\n bounds = Chartist.getBounds(this.svg, highLow, options, 0);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n // Start drawing\n var labels = this.svg.elem('g').addClass(options.classNames.labelGroup),\n grid = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = Chartist.projectPoint(chartRect, bounds, [0], 0, options),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createXAxis(chartRect, this.data, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n Chartist.createYAxis(chartRect, bounds, grid, labels, options, this.eventEmitter, this.supportsForeignObject);\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\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 = i - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfWidth = chartRect.width() / (normalizedData[i].length - (options.fullWidth ? 1 : 0)) / 2;\n\n seriesGroups[i] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n for(var j = 0; j < normalizedData[i].length; j++) {\n var p = Chartist.projectPoint(chartRect, bounds, normalizedData[i], j, options),\n bar,\n previousStack,\n y1,\n y2;\n\n // Offset to center bar between grid lines\n p.x += (options.centerBars ? periodHalfWidth : 0);\n // Using bi-polar offset for multiple series if no stacked bars are used\n p.x += options.stackBars ? 0 : biPol * options.seriesBarDistance;\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[j] || zeroPoint.y;\n stackedBarValues[j] = previousStack - (zeroPoint.y - p.y);\n\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n y1 = options.stackBars ? previousStack : zeroPoint.y;\n y2 = options.stackBars ? stackedBarValues[j] : p.y;\n\n bar = seriesGroups[i].elem('line', {\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n }, options.classNames.bar).attr({\n 'value': normalizedData[i][j],\n 'meta': this.data.series[i].data ?\n Chartist.serialize(this.data.series[i].data[j].meta) :\n Chartist.serialize(this.data.series[i][j].meta)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'bar',\n value: normalizedData[i][j],\n index: j,\n group: seriesGroups[i],\n element: bar,\n x1: p.x,\n y1: y1,\n x2: p.x,\n y2: y2\n });\n }\n }\n\n this.eventEmitter.emit('created', {\n bounds: bounds,\n chartRect: chartRect,\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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @returns {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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","axisY","xOffset","w","h","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","defaultOptions","position","count","move","line","curve","path","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","c","Path","m","l","seriesGroups","normalizedData","chart","StepAxis","Axis","stepCount","stretch","fullWidth","LinearScaleAxis","seriesIndex","series-name","pathCoordinates","valueIndex","showPoint","point","showLine","showArea","lineSmooth","cr","k","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.7.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.7.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height();\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @return {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n Chartist.Svg.Path.prototype.curve.apply(path, cr[k]);\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n path.line(pathCoordinates[l - 1], pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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: 40\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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);\n\n var valueAxis,\n labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index a03c4f46..44a00f41 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.6.1", + "version": "0.7.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index 98ff13bd..ad0b9d6e 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.6.1' + version: '0.7.0' }; (function (window, document, Chartist) { From 731d6983b79834ee8b2007b8034f49e3fba0a0c0 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 2 Feb 2015 11:24:32 +0100 Subject: [PATCH 173/593] Added missing files to concat task, fixes #176 --- tasks/concat.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks/concat.js b/tasks/concat.js index 595bde22..292ce626 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -24,6 +24,9 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/scripts/base.js', '<%= pkg.config.src %>/scripts/svg.js', '<%= pkg.config.src %>/scripts/svg-path.js', + '<%= pkg.config.src %>/scripts/axes/axis.js', + '<%= pkg.config.src %>/scripts/axes/linear-scale-axis.js', + '<%= pkg.config.src %>/scripts/axes/step-axis.js', '<%= pkg.config.src %>/scripts/charts/line.js', '<%= pkg.config.src %>/scripts/charts/bar.js', '<%= pkg.config.src %>/scripts/charts/pie.js' From 6e3d82963d40cd62005a7f031780da72787c1183 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 2 Feb 2015 11:30:49 +0100 Subject: [PATCH 174/593] Version bump to 0.7.1 --- CHANGELOG.md | 4 ++ bower.json | 2 +- dist/chartist.js | 119 ++++++++++++++++++++++++++++++++++++++- dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- src/scripts/core.js | 2 +- 8 files changed, 128 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ebcaf14..f4cab7d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v0.7.1 - 02 Feb 2015 +-------------------- +- Bug fix where some files where not included in dist version of Chartist which made v0.7.0 unusable. + v0.7.0 - 01 Feb 2015 -------------------- - This version introduces a new option in the bar charts to draw them horizontally diff --git a/bower.json b/bower.json index ced938ae..3ab285c6 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.7.0", + "version": "0.7.1", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 195e948d..55765e78 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { - /* Chartist.js 0.7.0 + /* Chartist.js 0.7.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.7.0' + version: '0.7.1' }; (function (window, document, Chartist) { @@ -2169,6 +2169,121 @@ Chartist.Svg.Path.elementDescriptions = elementDescriptions; }(window, document, Chartist)); + ;/** + * Axis base class used to implement different axis types + * + * @module Chartist.Axis + */ + /* global Chartist */ + (function (window, document, Chartist) { + 'use strict'; + + var axisUnits = { + x: { + pos: 'x', + len: 'width', + dir: 'horizontal', + rectStart: 'x1', + rectEnd: 'x2', + rectOffset: 'y2' + }, + y: { + pos: 'y', + len: 'height', + dir: 'vertical', + rectStart: 'y2', + rectEnd: 'y1', + rectOffset: 'x1' + } + }; + + function Axis(units, chartRect, transform, labelOffset, options) { + this.units = units; + this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; + this.chartRect = chartRect; + this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; + this.gridOffset = chartRect[units.rectOffset]; + this.transform = transform; + this.labelOffset = labelOffset; + this.options = options; + } + + Chartist.Axis = Chartist.Class.extend({ + constructor: Axis, + projectValue: function(value, index, data) { + throw new Error('Base axis can\'t be instantiated!'); + } + }); + + Chartist.Axis.units = axisUnits; + + }(window, document, Chartist)); + ;/** + * The linear scale axis uses standard linear scale projection of values along an axis. + * + * @module Chartist.LinearScaleAxis + */ + /* global Chartist */ + (function (window, document, Chartist) { + 'use strict'; + + function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) { + Chartist.LinearScaleAxis.super.constructor.call(this, + axisUnit, + chartRect, + transform, + labelOffset, + options); + + this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); + } + + function projectValue(value) { + return { + pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step), + len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) + }; + } + + Chartist.LinearScaleAxis = Chartist.Axis.extend({ + constructor: LinearScaleAxis, + projectValue: projectValue + }); + + }(window, document, Chartist)); + ;/** + * Step axis for step based charts like bar chart or step based line chart + * + * @module Chartist.StepAxis + */ + /* global Chartist */ + (function (window, document, Chartist) { + 'use strict'; + + function StepAxis(axisUnit, chartRect, transform, labelOffset, options) { + Chartist.StepAxis.super.constructor.call(this, + axisUnit, + chartRect, + transform, + labelOffset, + options); + + this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); + } + + function projectValue(value, index) { + return { + pos: this.stepLength * index, + len: this.stepLength + }; + } + + Chartist.StepAxis = Chartist.Axis.extend({ + constructor: StepAxis, + projectValue: projectValue + }); + + }(window, document, Chartist)); ;/** * 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. * diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 4c658a65..f4dd4e44 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.7.0 +/* Chartist.js 0.7.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index f3966c60..4626e6c0 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.7.0 +/* Chartist.js 0.7.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset||0:0,e=b.axisX?b.axisX.offset||0:0,f=c.stripUnit(b.width)||a.width(),g=c.stripUnit(b.height)||a.height();return{x1:b.chartPadding+d,y1:Math.max(g-b.chartPadding-e,b.chartPadding),x2:Math.max(f-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var l=c.catmullRom2bezier(j),m=0;ma.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset||0:0,e=b.axisX?b.axisX.offset||0:0,f=c.stripUnit(b.width)||a.width(),g=c.stripUnit(b.height)||a.height();return{x1:b.chartPadding+d,y1:Math.max(g-b.chartPadding-e,b.chartPadding),x2:Math.max(f-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var l=c.catmullRom2bezier(j),m=0;ma.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 0910720f..e5106efb 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","axisY","xOffset","w","h","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","defaultOptions","position","count","move","line","curve","path","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","c","Path","m","l","seriesGroups","normalizedData","chart","StepAxis","Axis","stepCount","stretch","fullWidth","LinearScaleAxis","seriesIndex","series-name","pathCoordinates","valueIndex","showPoint","point","showLine","showArea","lineSmooth","cr","k","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.7.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.7.0'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height();\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @return {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n Chartist.Svg.Path.prototype.curve.apply(path, cr[k]);\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n path.line(pathCoordinates[l - 1], pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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: 40\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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);\n\n var valueAxis,\n labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","axisY","xOffset","w","h","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","defaultOptions","position","count","move","line","curve","path","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","c","Path","m","l","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathCoordinates","valueIndex","showPoint","point","showLine","showArea","lineSmooth","cr","k","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.7.1\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.7.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height();\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @return {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n }(window, document, Chartist));\n ;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n }(window, document, Chartist));\n ;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n Chartist.Svg.Path.prototype.curve.apply(path, cr[k]);\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n path.line(pathCoordinates[l - 1], pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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: 40\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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);\n\n var valueAxis,\n labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index 44a00f41..c6ab5324 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.7.0", + "version": "0.7.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { diff --git a/src/scripts/core.js b/src/scripts/core.js index ad0b9d6e..0b2c80bb 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.7.0' + version: '0.7.1' }; (function (window, document, Chartist) { From 62b5834a16e3991d48644c32050debf7d3fd66a5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 2 Feb 2015 18:45:44 +0100 Subject: [PATCH 175/593] Refactored smoothing functionality into an interpolation module that's more maintainable and use the new SVG path API #92, fixes #155 --- site/layouts/default.hbs | 1 + src/scripts/charts/line.js | 33 ++++++----- src/scripts/interpolation.js | 105 +++++++++++++++++++++++++++++++++++ tasks/concat.js | 1 + 4 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 src/scripts/interpolation.js diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 581ad6e7..019bb689 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -52,6 +52,7 @@ + diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 1f463729..9af00f59 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -61,7 +61,7 @@ showArea: false, // The base for the area chart that will be used to close the area shape (is normally 0) areaBase: 0, - // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) + // 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. lineSmooth: true, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, @@ -219,20 +219,9 @@ // TODO: Nicer handling of conditions, maybe composition? if (options.showLine || options.showArea) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); - - // If smoothed path and path has more than two points then use catmull rom to bezier algorithm - if (options.lineSmooth && pathCoordinates.length > 4) { - - var cr = Chartist.catmullRom2bezier(pathCoordinates); - for(var k = 0; k < cr.length; k++) { - Chartist.Svg.Path.prototype.curve.apply(path, cr[k]); - } - } else { - for(var l = 3; l < pathCoordinates.length; l += 2) { - path.line(pathCoordinates[l - 1], pathCoordinates[l]); - } - } + var smoothing = typeof options.lineSmooth === 'function' ? + options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()), + path = smoothing(pathCoordinates); if(options.showLine) { var line = seriesGroups[seriesIndex].elem('path', { @@ -329,6 +318,20 @@ * new Chartist.Line('.ct-chart', data, options); * * @example + * // Use specific interpolation function with configuration from the Chartist.Interpolation module + * + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [ + * [1, 1, 8, 1, 7] + * ] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 0.2 + * }) + * }); + * + * @example * // Create a line chart with responsive options * * var data = { diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js new file mode 100644 index 00000000..7122220b --- /dev/null +++ b/src/scripts/interpolation.js @@ -0,0 +1,105 @@ +/** + * Chartist path interpolation functions. + * + * @module Chartist.Interpolation + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + Chartist.Interpolation = {}; + + /** + * This interpolation function does not smooth the path and the result is only containing lines and no curves. + * + * @memberof Chartist.Interpolation + * @return {Function} + */ + Chartist.Interpolation.none = function() { + return function cardinal(pathCoordinates) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + + for(var i = 3; i < pathCoordinates.length; i += 2) { + path.line(pathCoordinates[i - 1], pathCoordinates[i]); + } + + return path; + }; + }; + + /** + * 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. + * + * 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`. + * + * 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. + * + * The default configuration: + * ```javascript + * var defaultOptions = { + * tension: 1 + * }; + * ``` + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the cardinal factory function. + * @return {Function} + */ + Chartist.Interpolation.cardinal = function(options) { + var defaultOptions = { + tension: 1 + }; + + options = Chartist.extend({}, defaultOptions, options); + + var t = Math.min(1, Math.max(0, options.tension)), + c = 1 - t; + + return function cardinal(pathCoordinates) { + // If less than two points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return Chartist.Interpolation.none()(pathCoordinates); + } + + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]), + z; + + for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, + {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, + {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, + {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; + } else if (iLen - 4 === i) { + p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + } else if (iLen - 2 === i) { + p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; + } + } + + path.curve( + (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), + (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), + (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), + (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), + p[2].x, + p[2].y + ); + } + + return path; + }; + }; + +}(window, document, Chartist)); diff --git a/tasks/concat.js b/tasks/concat.js index 292ce626..582125d7 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -19,6 +19,7 @@ module.exports = function (grunt) { files: { '<%= pkg.config.dist %>/chartist.js': [ '<%= pkg.config.src %>/scripts/core.js', + '<%= pkg.config.src %>/scripts/interpolation.js', '<%= pkg.config.src %>/scripts/event.js', '<%= pkg.config.src %>/scripts/class.js', '<%= pkg.config.src %>/scripts/base.js', From a257ff9999d4b38b3e8c15c7dfe721cc71f671d4 Mon Sep 17 00:00:00 2001 From: "G. Kay Lee" Date: Tue, 3 Feb 2015 10:34:29 +0800 Subject: [PATCH 176/593] Update index.yml Fix a typo --- site/data/pages/index.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 35c7b59a..4f12c389 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -260,7 +260,7 @@ sections: data: text: > Almost limitless animation possibilities with the Chartist.Svg animation API. Checkout the - advanced getting stated guide about SVG + advanced getting started guide about SVG animations with SMIL. - title: Responsive charts configuration From fdf5045247a3982ed2db613091fcd7dc45b61008 Mon Sep 17 00:00:00 2001 From: Daniel Diekmeier Date: Wed, 11 Feb 2015 16:53:50 +0100 Subject: [PATCH 177/593] Add new simple smoothing function --- src/scripts/interpolation.js | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 7122220b..cb8637d5 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -27,6 +27,47 @@ }; }; + Chartist.Interpolation.simple = function(options) { + var defaultOptions = { + divisor: 2 + }; + options = Chartist.extend({}, defaultOptions, options); + + if (options.divisor == 0) { + var d = 1; + } else { + var d = 1 / options.divisor; + } + + return function simple(pathCoordinates) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + + // copy last coordinate so it's not undefined + pathCoordinates.push(pathCoordinates[pathCoordinates.length-1]); + pathCoordinates.push(pathCoordinates[pathCoordinates.length-3]); + + for(var i = 2; i <= pathCoordinates.length - 4; i += 2) { + // path.line(pathCoordinates[i - 1], pathCoordinates[i]); + var p = [ + {x: pathCoordinates[i - 2], y: pathCoordinates[i - 1]}, + {x: pathCoordinates[i], y: pathCoordinates[i + 1]}, + {x: pathCoordinates[i + 2], y: pathCoordinates[i + 3]} + ]; + + path.curve( + (p[0].x + ((p[1].x - p[0].x) * d)), + (p[0].y), + (p[1].x - ((p[1].x - p[0].x) * d)), + (p[1].y), + p[1].x, + p[1].y + ); + } + + return path; + }; + }; + /** * 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. * From ab9aa42344c53aae6427b81b4f249331663ba8a0 Mon Sep 17 00:00:00 2001 From: "G. Kay Lee" Date: Tue, 3 Feb 2015 10:34:29 +0800 Subject: [PATCH 178/593] Update index.yml Fix a typo --- site/data/pages/index.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 35c7b59a..4f12c389 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -260,7 +260,7 @@ sections: data: text: > Almost limitless animation possibilities with the Chartist.Svg animation API. Checkout the - advanced getting stated guide about SVG + advanced getting started guide about SVG animations with SMIL. - title: Responsive charts configuration From e3f65d32849f2a344489f9ee2b965a90a1c3e65e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 3 Feb 2015 19:54:51 +0100 Subject: [PATCH 179/593] Removed unused Class function --- src/scripts/class.js | 106 ------------------------------------------- 1 file changed, 106 deletions(-) diff --git a/src/scripts/class.js b/src/scripts/class.js index 9aa97c24..30ae475c 100644 --- a/src/scripts/class.js +++ b/src/scripts/class.js @@ -85,111 +85,6 @@ return constr; } - /** - * Creates a mixin from multiple super prototypes. - * - * @memberof Chartist.Class - * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. - * @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. - * @return {Function} Constructor function of the newly created mixin class - * - * @example - * var Fruit = Class.extend({ - * color: undefined, - * sugar: undefined, - * - * constructor: function(color, sugar) { - * this.color = color; - * this.sugar = sugar; - * }, - * - * eat: function() { - * this.sugar = 0; - * return this; - * } - * }); - * - * var Banana = Fruit.extend({ - * length: undefined, - * - * constructor: function(length, sugar) { - * Banana.super.constructor.call(this, 'Yellow', sugar); - * this.length = length; - * } - * }); - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * - * var KCal = Class.extend({ - * sugar: 0, - * - * constructor: function(sugar) { - * this.sugar = sugar; - * }, - * - * get kcal() { - * return [this.sugar * 4, 'kcal'].join(''); - * } - * }); - * - * var Nameable = Class.extend({ - * name: undefined, - * - * constructor: function(name) { - * this.name = name; - * } - * }); - * - * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { - * constructor: function(name, length, sugar) { - * Nameable.prototype.constructor.call(this, name); - * Banana.prototype.constructor.call(this, length, sugar); - * }, - * - * toString: function() { - * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); - * } - * }); - * - * - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); - * console.log(superBanana.toString()); - * - */ - function mix(mixProtoArr, properties) { - if(this !== Chartist.Class) { - throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); - } - - // Make sure our mixin prototypes are the class objects and not the constructors - var superPrototypes = [{}] - .concat(mixProtoArr) - .map(function (prototype) { - return prototype instanceof Function ? prototype.prototype : prototype; - }); - - var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); - // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype - delete mixedSuperProto.constructor; - return this.extend(properties, mixedSuperProto); - } - // Variable argument list clones args > 0 into args[0] and retruns modified args[0] function cloneDefinitions() { var args = listToArray(arguments); @@ -210,7 +105,6 @@ Chartist.Class = { extend: extend, - mix: mix, cloneDefinitions: cloneDefinitions }; From 9f22bcf130afd7b2d22e49d508baae24caea0330 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 12 Feb 2015 21:16:21 +0100 Subject: [PATCH 180/593] Refactored simple smoothing function and added documentation and example --- site/data/pages/examples.yml | 11 +++ .../examples/example-line-simple-smoothing.js | 15 ++++ src/scripts/interpolation.js | 72 +++++++++++-------- 3 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 site/examples/example-line-simple-smoothing.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 1870acaa..96e1be04 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -79,6 +79,17 @@ sections: intro: > Path animation is made easy with the SVG Path API. The API allows you to modify complex SVG paths and transform them for different animation morphing states. + - type: live-example + data: + title: Line Interpolation / Smoothing + level: 4 + id: example-line-simple-smoothing + classes: ct-golden-section + intro: > + By default Chartist uses a cardinal spline algorithm to smooth the lines. However, like all other + things in Chartist, this can be customized easily! Check out + the API Documentation for more + smoothing options. - title: Bar chart examples level: 3 items: diff --git a/site/examples/example-line-simple-smoothing.js b/site/examples/example-line-simple-smoothing.js new file mode 100644 index 00000000..caea4677 --- /dev/null +++ b/site/examples/example-line-simple-smoothing.js @@ -0,0 +1,15 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5], + series: [ + [1, 5, 10, 0, 1, 2], + [10, 15, 0, 1, 2, 3] + ] +}, { + // Remove this configuration to see that chart rendered with cardinal spline interpolation + // Sometimes, on large jumps in data values, it's better to use simple smoothing. + lineSmooth: Chartist.Interpolation.simple({ + divisor: 2 + }), + fullWidth: true, + low: 0 +}); diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index cb8637d5..ab0e45d8 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -27,40 +27,53 @@ }; }; + /** + * 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. + * + * 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. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.simple({ + * divisor: 2 + * }) + * }); + * + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the simple interpolation factory function. + * @return {Function} + */ Chartist.Interpolation.simple = function(options) { var defaultOptions = { divisor: 2 }; options = Chartist.extend({}, defaultOptions, options); - if (options.divisor == 0) { - var d = 1; - } else { - var d = 1 / options.divisor; - } + var d = 1 / Math.max(1, options.divisor); return function simple(pathCoordinates) { var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); - // copy last coordinate so it's not undefined - pathCoordinates.push(pathCoordinates[pathCoordinates.length-1]); - pathCoordinates.push(pathCoordinates[pathCoordinates.length-3]); - - for(var i = 2; i <= pathCoordinates.length - 4; i += 2) { - // path.line(pathCoordinates[i - 1], pathCoordinates[i]); - var p = [ - {x: pathCoordinates[i - 2], y: pathCoordinates[i - 1]}, - {x: pathCoordinates[i], y: pathCoordinates[i + 1]}, - {x: pathCoordinates[i + 2], y: pathCoordinates[i + 3]} - ]; + for(var i = 2; i < pathCoordinates.length; i += 2) { + var prevX = pathCoordinates[i - 2], + prevY = pathCoordinates[i - 1], + currX = pathCoordinates[i], + currY = pathCoordinates[i + 1], + length = (currX - prevX) * d; path.curve( - (p[0].x + ((p[1].x - p[0].x) * d)), - (p[0].y), - (p[1].x - ((p[1].x - p[0].x) * d)), - (p[1].y), - p[1].x, - p[1].y + prevX + length, + prevY, + currX - length, + currY, + currX, + currY ); } @@ -75,12 +88,15 @@ * * 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. * - * The default configuration: - * ```javascript - * var defaultOptions = { - * tension: 1 - * }; - * ``` + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 1 + * }) + * }); * * @memberof Chartist.Interpolation * @param {Object} options The options of the cardinal factory function. From cdc7e85e820f355b181135bcf414cb2130c5833e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 12 Feb 2015 21:17:19 +0100 Subject: [PATCH 181/593] Fixed path animation example --- site/examples/example-line-path-animation.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/site/examples/example-line-path-animation.js b/site/examples/example-line-path-animation.js index 66415d42..a216e0cc 100644 --- a/site/examples/example-line-path-animation.js +++ b/site/examples/example-line-path-animation.js @@ -1,5 +1,5 @@ var chart = new Chartist.Line('.ct-chart', { - labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], series: [ [1, 5, 2, 5, 4, 3], [2, 3, 4, 8, 1, 2], @@ -8,7 +8,8 @@ var chart = new Chartist.Line('.ct-chart', { }, { low: 0, showArea: true, - showPoint: false + showPoint: false, + fullWidth: true }); chart.on('draw', function(data) { From f707a11f7e9616334d25c56a54008ee936b6cf59 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 12 Feb 2015 21:35:21 +0100 Subject: [PATCH 182/593] Added inline docs badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 64af42df..5a60580a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") +[![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) + *Checkout the documentation site at http://gionkunz.github.io/chartist-js/* *Checkout this lightning talk that gives you an overview of Chartist in 5 minutes https://www.youtube.com/watch?v=WdYzPhOB_c8* From 389a8917a54aa78a90ed84bed99939369d1026b9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 12 Feb 2015 22:02:00 +0100 Subject: [PATCH 183/593] Only run travis with node 0.10 --- .travis.yml | 1 - tasks/jasmine.js | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 83f4e22f..a80b6e03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - - '0.8' - '0.10' before_script: - 'npm install -g bower grunt-cli' diff --git a/tasks/jasmine.js b/tasks/jasmine.js index 958dd53b..f3b7f4ce 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -14,10 +14,12 @@ module.exports = function (grunt) { dist: { src: [ '<%= pkg.config.src %>/scripts/core.js', + '<%= pkg.config.src %>/scripts/interpolation.js', '<%= pkg.config.src %>/scripts/event.js', '<%= pkg.config.src %>/scripts/class.js', '<%= pkg.config.src %>/scripts/base.js', '<%= pkg.config.src %>/scripts/svg.js', + '<%= pkg.config.src %>/scripts/svg-path.js', '<%= pkg.config.src %>/scripts/axes/axis.js', '<%= pkg.config.src %>/scripts/axes/step-axis.js', '<%= pkg.config.src %>/scripts/axes/linear-scale-axis.js', From f5a65b655f400e7d5d09b68442eef0652903f368 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 12 Feb 2015 22:13:24 +0100 Subject: [PATCH 184/593] Fixed tests after jasmine update --- test/spec/spec-core.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 9f4ac92d..49644318 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -53,12 +53,12 @@ describe('Chartist core', function() { it('should serialize and deserialize numbers', function() { var input = 12345.6789; - expect(input).toMatch(Chartist.deserialize(Chartist.serialize(input))); + expect(input).toEqual(Chartist.deserialize(Chartist.serialize(input))); }); it('should serialize and deserialize dates', function() { var input = new Date(0); - expect(+input).toMatch(+new Date(Chartist.deserialize(Chartist.serialize(input)))); + expect(+input).toEqual(+new Date(Chartist.deserialize(Chartist.serialize(input)))); }); it('should serialize and deserialize complex object types', function() { @@ -73,12 +73,12 @@ describe('Chartist core', function() { } }; - expect(input).toMatch(Chartist.deserialize(Chartist.serialize(input))); + expect(input).toEqual(Chartist.deserialize(Chartist.serialize(input))); }); it('should serialize and deserialize null, undefined and NaN', function() { - expect(null).toMatch(Chartist.deserialize(Chartist.serialize(null))); - expect(undefined).toMatch(Chartist.deserialize(Chartist.serialize(undefined))); + expect(null).toEqual(Chartist.deserialize(Chartist.serialize(null))); + expect(undefined).toEqual(Chartist.deserialize(Chartist.serialize(undefined))); expect(NaN).toMatch(Chartist.deserialize(Chartist.serialize('NaN'))); }); }); From 3c23048374f9e5de7d96abc9306fcecf40900bf4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 12 Feb 2015 22:30:36 +0100 Subject: [PATCH 185/593] Adding badges --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a60580a..fcbeba69 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # Big welcome by the Chartist Guy +[![npm version](http://img.shields.io/npm/v/chartist.svg)](https://npmjs.org/package/chartist) [![build status](http://img.shields.io/travis/gionkunz/chartist-js.svg)](https://travis-ci.org/gionkunz/chartist-js) [![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) ![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") -[![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) - *Checkout the documentation site at http://gionkunz.github.io/chartist-js/* *Checkout this lightning talk that gives you an overview of Chartist in 5 minutes https://www.youtube.com/watch?v=WdYzPhOB_c8* From 6cf68d271f1e291b7a9d0fb7788c1c0464cb4d37 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 12 Feb 2015 22:43:34 +0100 Subject: [PATCH 186/593] Version bump to 0.7.2 --- CHANGELOG.md | 6 + bower.json | 2 +- dist/chartist.js | 303 +++++++++++++++++++++++---------------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 4 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- 7 files changed, 193 insertions(+), 128 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4cab7d4..45ede1cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v0.7.2 - 12 Feb 2015 +-------------------- +- Added new line smoothing / interpolation module for configurable line smoothing +- Added simple line smoothing. Thanks @danieldiekmeier ! +- Removed some unused internal code + v0.7.1 - 02 Feb 2015 -------------------- - Bug fix where some files where not included in dist version of Chartist which made v0.7.0 unusable. diff --git a/bower.json b/bower.json index 3ab285c6..cbb6c5c9 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.7.1", + "version": "0.7.2", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 55765e78..d0b4c0a5 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { - /* Chartist.js 0.7.1 + /* Chartist.js 0.7.2 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -792,6 +792,168 @@ return d; }; + }(window, document, Chartist)); + ;/** + * Chartist path interpolation functions. + * + * @module Chartist.Interpolation + */ + /* global Chartist */ + (function(window, document, Chartist) { + 'use strict'; + + Chartist.Interpolation = {}; + + /** + * This interpolation function does not smooth the path and the result is only containing lines and no curves. + * + * @memberof Chartist.Interpolation + * @return {Function} + */ + Chartist.Interpolation.none = function() { + return function cardinal(pathCoordinates) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + + for(var i = 3; i < pathCoordinates.length; i += 2) { + path.line(pathCoordinates[i - 1], pathCoordinates[i]); + } + + return path; + }; + }; + + /** + * 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. + * + * 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. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.simple({ + * divisor: 2 + * }) + * }); + * + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the simple interpolation factory function. + * @return {Function} + */ + Chartist.Interpolation.simple = function(options) { + var defaultOptions = { + divisor: 2 + }; + options = Chartist.extend({}, defaultOptions, options); + + var d = 1 / Math.max(1, options.divisor); + + return function simple(pathCoordinates) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + + for(var i = 2; i < pathCoordinates.length; i += 2) { + var prevX = pathCoordinates[i - 2], + prevY = pathCoordinates[i - 1], + currX = pathCoordinates[i], + currY = pathCoordinates[i + 1], + length = (currX - prevX) * d; + + path.curve( + prevX + length, + prevY, + currX - length, + currY, + currX, + currY + ); + } + + return path; + }; + }; + + /** + * 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. + * + * 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`. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 1 + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the cardinal factory function. + * @return {Function} + */ + Chartist.Interpolation.cardinal = function(options) { + var defaultOptions = { + tension: 1 + }; + + options = Chartist.extend({}, defaultOptions, options); + + var t = Math.min(1, Math.max(0, options.tension)), + c = 1 - t; + + return function cardinal(pathCoordinates) { + // If less than two points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return Chartist.Interpolation.none()(pathCoordinates); + } + + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]), + z; + + for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, + {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, + {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, + {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; + } else if (iLen - 4 === i) { + p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + } else if (iLen - 2 === i) { + p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; + } + } + + path.curve( + (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), + (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), + (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), + (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), + p[2].x, + p[2].y + ); + } + + return path; + }; + }; + }(window, document, Chartist)); ;/** * A very basic event module that helps to generate and catch events. @@ -958,111 +1120,6 @@ return constr; } - /** - * Creates a mixin from multiple super prototypes. - * - * @memberof Chartist.Class - * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors. - * @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. - * @return {Function} Constructor function of the newly created mixin class - * - * @example - * var Fruit = Class.extend({ - * color: undefined, - * sugar: undefined, - * - * constructor: function(color, sugar) { - * this.color = color; - * this.sugar = sugar; - * }, - * - * eat: function() { - * this.sugar = 0; - * return this; - * } - * }); - * - * var Banana = Fruit.extend({ - * length: undefined, - * - * constructor: function(length, sugar) { - * Banana.super.constructor.call(this, 'Yellow', sugar); - * this.length = length; - * } - * }); - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * - * var KCal = Class.extend({ - * sugar: 0, - * - * constructor: function(sugar) { - * this.sugar = sugar; - * }, - * - * get kcal() { - * return [this.sugar * 4, 'kcal'].join(''); - * } - * }); - * - * var Nameable = Class.extend({ - * name: undefined, - * - * constructor: function(name) { - * this.name = name; - * } - * }); - * - * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], { - * constructor: function(name, length, sugar) { - * Nameable.prototype.constructor.call(this, name); - * Banana.prototype.constructor.call(this, length, sugar); - * }, - * - * toString: function() { - * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' '); - * } - * }); - * - * - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - * - * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80); - * console.log(superBanana.toString()); - * - */ - function mix(mixProtoArr, properties) { - if(this !== Chartist.Class) { - throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!'); - } - - // Make sure our mixin prototypes are the class objects and not the constructors - var superPrototypes = [{}] - .concat(mixProtoArr) - .map(function (prototype) { - return prototype instanceof Function ? prototype.prototype : prototype; - }); - - var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes); - // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype - delete mixedSuperProto.constructor; - return this.extend(properties, mixedSuperProto); - } - // Variable argument list clones args > 0 into args[0] and retruns modified args[0] function cloneDefinitions() { var args = listToArray(arguments); @@ -1083,7 +1140,6 @@ Chartist.Class = { extend: extend, - mix: mix, cloneDefinitions: cloneDefinitions }; @@ -2347,7 +2403,7 @@ showArea: false, // The base for the area chart that will be used to close the area shape (is normally 0) areaBase: 0, - // Specify if the lines should be smoothed (Catmull-Rom-Splines will be used) + // 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. lineSmooth: true, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, @@ -2505,20 +2561,9 @@ // TODO: Nicer handling of conditions, maybe composition? if (options.showLine || options.showArea) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); - - // If smoothed path and path has more than two points then use catmull rom to bezier algorithm - if (options.lineSmooth && pathCoordinates.length > 4) { - - var cr = Chartist.catmullRom2bezier(pathCoordinates); - for(var k = 0; k < cr.length; k++) { - Chartist.Svg.Path.prototype.curve.apply(path, cr[k]); - } - } else { - for(var l = 3; l < pathCoordinates.length; l += 2) { - path.line(pathCoordinates[l - 1], pathCoordinates[l]); - } - } + var smoothing = typeof options.lineSmooth === 'function' ? + options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()), + path = smoothing(pathCoordinates); if(options.showLine) { var line = seriesGroups[seriesIndex].elem('path', { @@ -2615,6 +2660,20 @@ * new Chartist.Line('.ct-chart', data, options); * * @example + * // Use specific interpolation function with configuration from the Chartist.Interpolation module + * + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [ + * [1, 1, 8, 1, 7] + * ] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 0.2 + * }) + * }); + * + * @example * // Create a line chart with responsive options * * var data = { diff --git a/dist/chartist.min.css b/dist/chartist.min.css index f4dd4e44..fce5d082 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,4 +1,4 @@ -/* Chartist.js 0.7.1 +/* Chartist.js 0.7.2 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 4626e6c0..df6e1d07 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.7.1 +/* Chartist.js 0.7.2 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset||0:0,e=b.axisX?b.axisX.offset||0:0,f=c.stripUnit(b.width)||a.width(),g=c.stripUnit(b.height)||a.height();return{x1:b.chartPadding+d,y1:Math.max(g-b.chartPadding-e,b.chartPadding),x2:Math.max(f-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;c4)for(var l=c.catmullRom2bezier(j),m=0;ma.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie.super.constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset||0:0,e=b.axisX?b.axisX.offset||0:0,f=c.stripUnit(b.width)||a.width(),g=c.stripUnit(b.height)||a.height();return{x1:b.chartPadding+d,y1:Math.max(g-b.chartPadding-e,b.chartPadding),x2:Math.max(f-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.Interpolation={},c.Interpolation.none=function(){return function(a){for(var b=(new c.Svg.Path).move(a[0],a[1]),d=3;dg;g+=2){var i=[{x:+a[g-2],y:+a[g-1]},{x:+a[g],y:+a[g+1]},{x:+a[g+2],y:+a[g+3]},{x:+a[g+4],y:+a[g+5]}];b?g?h-4===g?i[3]={x:+a[0],y:+a[1]}:h-2===g&&(i[2]={x:+a[0],y:+a[1]},i[3]={x:+a[2],y:+a[3]}):i[0]={x:+a[h-2],y:+a[h-1]}:h-4===g?i[3]=i[2]:g||(i[0]={x:+a[g],y:+a[g+1]}),f.curve(d*(-i[0].x+6*i[1].x+i[2].x)/6+e*i[2].x,d*(-i[0].y+6*i[1].y+i[2].y)/6+e*i[2].y,d*(i[1].x+6*i[2].x-i[3].x)/6+e*i[2].x,d*(i[1].y+6*i[2].y-i[3].y)/6+e*i[2].y,i[2].x,i[2].y)}return f}}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;ca.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie["super"].constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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/dist/chartist.min.js.map b/dist/chartist.min.js.map index e5106efb..b3f01d4d 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","axisY","xOffset","w","h","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","super","mix","mixProtoArr","Error","superPrototypes","concat","Function","mixedSuperProto","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","t","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","defaultOptions","position","count","move","line","curve","path","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","c","Path","m","l","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathCoordinates","valueIndex","showPoint","point","showLine","showArea","lineSmooth","cr","k","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.7.1\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.7.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height();\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\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 /**\n * Creates a mixin from multiple super prototypes.\n *\n * @memberof Chartist.Class\n * @param {Array} mixProtoArr An array of super prototypes or an array of super prototype constructors.\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 * @return {Function} Constructor function of the newly created mixin 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 *\n * var KCal = Class.extend({\n * sugar: 0,\n *\n * constructor: function(sugar) {\n * this.sugar = sugar;\n * },\n *\n * get kcal() {\n * return [this.sugar * 4, 'kcal'].join('');\n * }\n * });\n *\n * var Nameable = Class.extend({\n * name: undefined,\n *\n * constructor: function(name) {\n * this.name = name;\n * }\n * });\n *\n * var NameableKCalBanana = Class.mix([Banana, KCal, Nameable], {\n * constructor: function(name, length, sugar) {\n * Nameable.prototype.constructor.call(this, name);\n * Banana.prototype.constructor.call(this, length, sugar);\n * },\n *\n * toString: function() {\n * return [this.name, 'with', this.length + 'cm', 'and', this.kcal].join(' ');\n * }\n * });\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 * var superBanana = new NameableKCalBanana('Super Mixin Banana', 30, 80);\n * console.log(superBanana.toString());\n *\n */\n function mix(mixProtoArr, properties) {\n if(this !== Chartist.Class) {\n throw new Error('Chartist.Class.mix should only be called on the type and never on an instance!');\n }\n\n // Make sure our mixin prototypes are the class objects and not the constructors\n var superPrototypes = [{}]\n .concat(mixProtoArr)\n .map(function (prototype) {\n return prototype instanceof Function ? prototype.prototype : prototype;\n });\n\n var mixedSuperProto = Chartist.Class.cloneDefinitions.apply(undefined, superPrototypes);\n // Delete the constructor if present because we don't want to invoke a constructor on a mixed prototype\n delete mixedSuperProto.constructor;\n return this.extend(properties, mixedSuperProto);\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 mix: mix,\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n }(window, document, Chartist));\n ;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n }(window, document, Chartist));\n ;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 (Catmull-Rom-Splines will be used)\n lineSmooth: true,\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\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n // If smoothed path and path has more than two points then use catmull rom to bezier algorithm\n if (options.lineSmooth && pathCoordinates.length > 4) {\n\n var cr = Chartist.catmullRom2bezier(pathCoordinates);\n for(var k = 0; k < cr.length; k++) {\n Chartist.Svg.Path.prototype.curve.apply(path, cr[k]);\n }\n } else {\n for(var l = 3; l < pathCoordinates.length; l += 2) {\n path.line(pathCoordinates[l - 1], pathCoordinates[l]);\n }\n }\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 * // 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 adition 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 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 // 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: 40\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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);\n\n var valueAxis,\n labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","axisY","xOffset","w","h","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","Interpolation","none","pathCoordinates","path","Path","move","line","simple","defaultOptions","divisor","prevX","prevY","currX","currY","curve","cardinal","tension","t","c","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","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","position","count","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","m","l","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","valueIndex","showPoint","point","showLine","showArea","smoothing","lineSmooth","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.7.2\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.7.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height();\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function cardinal(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 3; i < pathCoordinates.length; i += 2) {\n path.line(pathCoordinates[i - 1], pathCoordinates[i]);\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 * })\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 };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2],\n prevY = pathCoordinates[i - 1],\n currX = pathCoordinates[i],\n currY = pathCoordinates[i + 1],\n length = (currX - prevX) * d;\n\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY\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 * })\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 };\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) {\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]),\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 );\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n }(window, document, Chartist));\n ;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n }(window, document, Chartist));\n ;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 // 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\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var smoothing = typeof options.lineSmooth === 'function' ?\n options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()),\n path = smoothing(pathCoordinates);\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 adition 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 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 // 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: 40\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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);\n\n var valueAxis,\n labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index c6ab5324..8783524c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.7.1", + "version": "0.7.2", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 80afb206a639a7dd82dd1d25136445c3d8e3e800 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 14 Feb 2015 09:48:12 +0100 Subject: [PATCH 187/593] Updated to latest NPM deps --- package.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 8783524c..69296b1a 100644 --- a/package.json +++ b/package.json @@ -42,24 +42,24 @@ "grunt-contrib-concat": "^0.5.0", "grunt-contrib-connect": "~0.9.0", "grunt-contrib-copy": "^0.7.0", - "grunt-contrib-cssmin": "^0.10.0", - "grunt-contrib-htmlmin": "~0.3.0", - "grunt-contrib-imagemin": "~0.9.2", - "grunt-contrib-jasmine": "~0.8.1", - "grunt-contrib-jshint": "~0.10.0", - "grunt-contrib-uglify": "^0.6.0", + "grunt-contrib-cssmin": "^0.12.1", + "grunt-contrib-htmlmin": "~0.4.0", + "grunt-contrib-imagemin": "~0.9.3", + "grunt-contrib-jasmine": "~0.8.2", + "grunt-contrib-jshint": "~0.11.0", + "grunt-contrib-uglify": "^0.7.0", "grunt-contrib-watch": "^0.6.1", - "grunt-critical": "0.0.3", - "grunt-newer": "^0.8.0", - "grunt-sass": "^0.16.1", + "grunt-critical": "0.1.1", + "grunt-newer": "^1.1.0", + "grunt-sass": "^0.18.0", "grunt-svgmin": "~2.0.0", - "grunt-umd": "~2.2.1", - "grunt-usemin": "~2.6.2", + "grunt-umd": "~2.3.1", + "grunt-usemin": "~3.0.0", "handlebars-helpers": "~0.5.8", - "jasmine-jquery": "~2.0.5", + "jasmine-jquery": "~2.0.6", "jshint-stylish": "~1.0.0", "load-grunt-config": "^0.16.0", - "lodash": "^2.4.1", + "lodash": "~2.4.1", "seed-random": "~2.2.0", "time-grunt": "^1.0.0" }, From 3068d244d65a087b23e85053e52680f68bcf0b74 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 14 Feb 2015 10:09:11 +0100 Subject: [PATCH 188/593] Updated bower dependencies --- bower.json | 6 +++--- site/styles/_code-mirror-theme.scss | 4 ++++ site/styles/settings/_foundation.scss | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/bower.json b/bower.json index cbb6c5c9..036429e1 100644 --- a/bower.json +++ b/bower.json @@ -7,10 +7,10 @@ ], "devDependencies": { "snap.svg": "~0.3.0", - "foundation": "~5.4.7", - "highlightjs": "~8.3.0", + "foundation": "~5.5.1", + "highlightjs": "~8.4.0", "compass-mixins": "~1.0.2", - "codemirror": "~4.8.0", + "codemirror": "~4.12.0", "base64": "~0.3.0", "chartist-plugin-pointlabels": "~0.0.2", "chartist-plugin-sketchy": "~0.0.1" diff --git a/site/styles/_code-mirror-theme.scss b/site/styles/_code-mirror-theme.scss index b5209ec8..8e7eaa89 100644 --- a/site/styles/_code-mirror-theme.scss +++ b/site/styles/_code-mirror-theme.scss @@ -1,3 +1,7 @@ +.CodeMirror-scroll { + overflow: auto !important; +} + .cm-s-chartist.CodeMirror { background: $color-black; color: lighten($color-white, 10%); diff --git a/site/styles/settings/_foundation.scss b/site/styles/settings/_foundation.scss index 23fcd60f..67499c4b 100644 --- a/site/styles/settings/_foundation.scss +++ b/site/styles/settings/_foundation.scss @@ -1361,7 +1361,7 @@ $topbar-bg-color: $color-gray; $topbar-bg: $topbar-bg-color; // Height and margin -$topbar-height: 45px; +$topbar-height: rem-calc(45px); $topbar-margin-bottom: 0; // Controlling the styles for the title in the top bar From ab8a5f23b85d4f4b6267c0c81770636baee8aac9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 27 Feb 2015 16:09:06 +0100 Subject: [PATCH 189/593] Fixed chart update function options override and double creation issue, fixes #206 --- src/scripts/base.js | 11 +- src/scripts/charts/bar.js | 1 + src/scripts/charts/line.js | 1 + src/scripts/charts/pie.js | 1 + src/scripts/core.js | 6 +- test/spec/spec-base-chart.js | 206 +++++++++++++++++++++++++++++++++++ 6 files changed, 219 insertions(+), 7 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index 2ae51dc4..7afb5bd8 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -18,10 +18,10 @@ * * @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. * @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. - * @param {Boolean} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already. + * @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 * @memberof Chartist.Base */ - function update(data, options, extendObjects) { + function update(data, options, override) { if(data) { this.data = data; // Event for data transformation that allows to manipulate the data before it gets rendered in the charts @@ -32,9 +32,10 @@ } if(options) { - this.options = Chartist.extend({}, extendObjects ? this.options : {}, options); + this.options = Chartist.extend({}, override ? this.options : this.defaultOptions, options); // If chartist was not initialized yet, we just set the options and leave the rest to the initialization + // Otherwise we re-create the optionsProvider at this point if(!this.initializeTimeoutId) { this.optionsProvider.removeMediaQueryListeners(); this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); @@ -128,13 +129,15 @@ * * @param query * @param data + * @param defaultOptions * @param options * @param responsiveOptions * @constructor */ - function Base(query, data, options, responsiveOptions) { + function Base(query, data, defaultOptions, options, responsiveOptions) { this.container = Chartist.querySelector(query); this.data = data; + this.defaultOptions = defaultOptions; this.options = options; this.responsiveOptions = responsiveOptions; this.eventEmitter = Chartist.EventEmitter(); diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 59b2a600..10f636d3 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -323,6 +323,7 @@ Chartist.Bar.super.constructor.call(this, query, data, + defaultOptions, Chartist.extend({}, defaultOptions, options), responsiveOptions); } diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 9af00f59..3c602a97 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -372,6 +372,7 @@ Chartist.Line.super.constructor.call(this, query, data, + defaultOptions, Chartist.extend({}, defaultOptions, options), responsiveOptions); } diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index b4d210c1..b55e5cc0 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -289,6 +289,7 @@ Chartist.Pie.super.constructor.call(this, query, data, + defaultOptions, Chartist.extend({}, defaultOptions, options), responsiveOptions); } diff --git a/src/scripts/core.js b/src/scripts/core.js index 0b2c80bb..c789f15a 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -682,7 +682,7 @@ var Chartist = { mediaQueryListeners = [], i; - function updateCurrentOptions() { + function updateCurrentOptions(preventChangedEvent) { var previousOptions = currentOptions; currentOptions = Chartist.extend({}, baseOptions); @@ -695,7 +695,7 @@ var Chartist = { } } - if(eventEmitter) { + if(eventEmitter && !preventChangedEvent) { eventEmitter.emit('optionsChanged', { previousOptions: previousOptions, currentOptions: currentOptions @@ -720,7 +720,7 @@ var Chartist = { } } // Execute initially so we get the correct options - updateCurrentOptions(); + updateCurrentOptions(true); return { get currentOptions() { diff --git a/test/spec/spec-base-chart.js b/test/spec/spec-base-chart.js index a8f01345..bf36a139 100644 --- a/test/spec/spec-base-chart.js +++ b/test/spec/spec-base-chart.js @@ -62,4 +62,210 @@ describe('Base chart tests', function() { done(); }); }); + + it('should update correctly with data only in same call stack', function(done) { + jasmine.getFixtures().set('
    '); + + var dataEventsSpy = jasmine.createSpy('dataEventSpy'); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }); + + var updatedData = { + labels: [1, 2, 3, 4], + series: [[3, 2, 1, 0]] + }; + + chart.update(updatedData); + + chart.on('data', dataEventsSpy); + + chart.on('created', function() { + expect(chart.data.series[0]).toEqual([3, 2, 1, 0]); + // As called in same call stack we should only have one data event (the initial one) + expect(dataEventsSpy.calls.count()).toBe(1); + expect(dataEventsSpy.calls.argsFor(0)[0].type).toBe('initial'); + done(); + }); + }); + + it('should update correctly with data only in a different call stack', function(done) { + jasmine.getFixtures().set('
    '); + + var dataEventsSpy = jasmine.createSpy('dataEventSpy'); + + var createdCount = 0; + + var initialData = { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }; + + var updatedData = { + labels: [1, 2, 3, 4], + series: [[3, 2, 1, 0]] + }; + + var chart = new Chartist.Line('.ct-chart', initialData); + + setTimeout(function() { + chart.update(updatedData); + }); + + chart.on('data', dataEventsSpy); + + // On the second created event we will finish and evaluate the test + chart.on('created', function() { + createdCount++; + + if(createdCount === 2) { + expect(chart.data.series[0]).toEqual([3, 2, 1, 0]); + // Called from a later call stack in the event loop, there should be two data update counts now + expect(dataEventsSpy.calls.count()).toBe(2); + expect(dataEventsSpy.calls.argsFor(0)[0].type).toBe('initial'); + expect(dataEventsSpy.calls.argsFor(0)[0].data).toEqual(initialData); + expect(dataEventsSpy.calls.argsFor(1)[0].type).toBe('update'); + expect(dataEventsSpy.calls.argsFor(1)[0].data).toEqual(updatedData); + done(); + } + }); + }); + + it('should update correctly with options only in same call stack', function(done) { + jasmine.getFixtures().set('
    '); + + var dataEventsSpy = jasmine.createSpy('dataEventSpy'); + var optionsChangedEventsSpy = jasmine.createSpy('optionsChangedEventsSpy'); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }, { + showArea: true, + showPoint: false + }); + + var updatedOptions = { + showArea: false, + showPoint: true + }; + + chart.update(null, updatedOptions); + + chart.on('data', dataEventsSpy); + chart.on('optionsChanged', optionsChangedEventsSpy); + + chart.on('created', function() { + // Data has not been updated and only initialized, therefore the initial type and only 1 call + expect(dataEventsSpy.calls.count()).toBe(1); + expect(dataEventsSpy.calls.argsFor(0)[0].type).toBe('initial'); + + // Options changed should not be fired as called in same call stack + expect(optionsChangedEventsSpy.calls.count()).toBe(0); + + // Updated options should be present as we updated it in same call stack before chart creation + expect(chart.optionsProvider.currentOptions.showArea).toBe(false); + expect(chart.optionsProvider.currentOptions.showPoint).toBe(true); + done(); + }); + }); + + it('should update correctly with options only in a different call stack', function(done) { + jasmine.getFixtures().set('
    '); + + var createdCount = 0; + var dataEventsSpy = jasmine.createSpy('dataEventSpy'); + var optionsChangedEventsSpy = jasmine.createSpy('optionsChangedEventsSpy'); + + var initialData = { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }; + + var chart = new Chartist.Line('.ct-chart', initialData, { + showArea: true, + showPoint: false + }); + + var updatedOptions = { + showArea: false, + showPoint: true + }; + + setTimeout(function() { + chart.update(null, updatedOptions); + }); + + chart.on('data', dataEventsSpy); + chart.on('optionsChanged', optionsChangedEventsSpy); + + chart.on('created', function() { + createdCount++; + + // On the second created event we will finish and evaluate the test + if(createdCount === 2) { + // Called from a later call stack in the event loop, there should be two data update counts now + expect(dataEventsSpy.calls.count()).toBe(1); + expect(dataEventsSpy.calls.argsFor(0)[0].type).toBe('initial'); + expect(dataEventsSpy.calls.argsFor(0)[0].data).toEqual(initialData); + + // Update should not cause any optionsChanged event + expect(optionsChangedEventsSpy.calls.count()).toBe(0); + + done(); + } + }); + }); + + it('should update options with override=false correctly', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }, { + showArea: true + }); + + var updatedOptions = { + showPoint: false + }; + + // With override set to true, the previous option showArea=true should still be available on chart creation + chart.update(null, updatedOptions); + + chart.on('created', function() { + // showArea is false in the default settings and as we didn't use current options and override option it should + // be back to default. + expect(chart.optionsProvider.currentOptions.showArea).toBe(false); + expect(chart.optionsProvider.currentOptions.showPoint).toBe(false); + done(); + }); + }); + + it('should update options with override=true correctly', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4], + series: [[0, 1, 2, 3]] + }, { + showArea: true + }); + + var updatedOptions = { + showPoint: false + }; + + // With override set to true, the previous option showArea=true should still be available on chart creation + chart.update(null, updatedOptions, true); + + chart.on('created', function() { + expect(chart.optionsProvider.currentOptions.showArea).toBe(true); + expect(chart.optionsProvider.currentOptions.showPoint).toBe(false); + done(); + }); + }); }); From aebc8f25b38b937123d4214be86d7e5d0521bcac Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 27 Feb 2015 16:10:47 +0100 Subject: [PATCH 190/593] Removed unused function that was moved to Chartist.Interpolation --- src/scripts/core.js | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index c789f15a..96db9a42 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -730,45 +730,4 @@ var Chartist = { }; }; - //http://schepers.cc/getting-to-the-point - Chartist.catmullRom2bezier = function (crp, z) { - var d = []; - for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { - var p = [ - {x: +crp[i - 2], y: +crp[i - 1]}, - {x: +crp[i], y: +crp[i + 1]}, - {x: +crp[i + 2], y: +crp[i + 3]}, - {x: +crp[i + 4], y: +crp[i + 5]} - ]; - if (z) { - if (!i) { - p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; - } else if (iLen - 4 === i) { - p[3] = {x: +crp[0], y: +crp[1]}; - } else if (iLen - 2 === i) { - p[2] = {x: +crp[0], y: +crp[1]}; - p[3] = {x: +crp[2], y: +crp[3]}; - } - } else { - if (iLen - 4 === i) { - p[3] = p[2]; - } else if (!i) { - p[0] = {x: +crp[i], y: +crp[i + 1]}; - } - } - d.push( - [ - (-p[0].x + 6 * p[1].x + p[2].x) / 6, - (-p[0].y + 6 * p[1].y + p[2].y) / 6, - (p[1].x + 6 * p[2].x - p[3].x) / 6, - (p[1].y + 6 * p[2].y - p[3].y) / 6, - p[2].x, - p[2].y - ] - ); - } - - return d; - }; - }(window, document, Chartist)); From 6cfcc8d3a478f0b99e02867cf74630c42467bf2e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 27 Feb 2015 17:02:34 +0100 Subject: [PATCH 191/593] Added template plugin to replace version in js file dynamically on build time --- package.json | 1 + src/scripts/core.js | 2 +- tasks/aliases.yml | 1 + tasks/template.js | 27 +++++++++++++++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tasks/template.js diff --git a/package.json b/package.json index 69296b1a..00cc6c7f 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "grunt-newer": "^1.1.0", "grunt-sass": "^0.18.0", "grunt-svgmin": "~2.0.0", + "grunt-template": "^0.2.3", "grunt-umd": "~2.3.1", "grunt-usemin": "~3.0.0", "handlebars-helpers": "~0.5.8", diff --git a/src/scripts/core.js b/src/scripts/core.js index 96db9a42..20ea1071 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -4,7 +4,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.7.1' + version: '<%= pkg.version %>' }; (function (window, document, Chartist) { diff --git a/tasks/aliases.yml b/tasks/aliases.yml index e35f3ebd..0142ed10 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -14,6 +14,7 @@ build: - 'clean:dist' - 'copy:dist' - 'concat:dist' + - 'template:dist' - 'umd' - 'uglify:dist' - 'sass:dist' diff --git a/tasks/template.js b/tasks/template.js new file mode 100644 index 00000000..4e84e014 --- /dev/null +++ b/tasks/template.js @@ -0,0 +1,27 @@ +/** + * template + * === + * + * Replaces template variables inside of files using build stage variables. + * + * Link: https://github.com/mathiasbynens/grunt-template + */ + +'use strict'; + +var pkg = require('../package.json'); + +module.exports = function (grunt) { + return { + dist: { + options: { + data: { + pkg: pkg + } + }, + files: { + '<%= pkg.config.dist %>/chartist.js': '<%= pkg.config.dist %>/chartist.js' + } + } + }; +}; From 994288576abdd6f0668f52958fb0667b712aa587 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 27 Feb 2015 17:22:39 +0100 Subject: [PATCH 192/593] Added default rounding of 8 digits after decimal for OOM steps, fixes #110 --- src/scripts/core.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 20ea1071..176e4796 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -161,6 +161,27 @@ var Chartist = { return result; }; + /** + * 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. + * + * @memberof Chartist.Core + * @param {Number} value The value that should be rounded with precision + * @param {Number} [digits] The number of digits after decimal used to do the rounding + * @returns {number} Rounded value + */ + Chartist.roundWithPrecision = function(value, digits) { + var precision = Math.pow(10, digits || Chartist.precision); + return Math.round(value * precision) / precision; + }; + + /** + * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number. + * + * @memberof Chartist.Core + * @type {number} + */ + Chartist.precision = 8; + /** * A map with characters to escape for strings to be safely used as attribute values. * @@ -498,7 +519,7 @@ var Chartist = { bounds.values = []; for (i = bounds.min; i <= bounds.max; i += bounds.step) { - bounds.values.push(i); + bounds.values.push(Chartist.roundWithPrecision(i)); } return bounds; From db33abd63cfe9eb5327bfaacf8a8dc6153f9f09e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 27 Feb 2015 18:19:36 +0100 Subject: [PATCH 193/593] Fixed nasty bug in Chartist.extend where object properties were modified in source during merge --- src/scripts/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 176e4796..c3097ae5 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -48,7 +48,7 @@ var Chartist = { sources.forEach(function(source) { for (var prop in source) { if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) { - target[prop] = Chartist.extend(target[prop], source[prop]); + target[prop] = Chartist.extend({}, target[prop], source[prop]); } else { target[prop] = source[prop]; } From 6907908bbee1e903c89339234ec6ed8c08285616 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 27 Feb 2015 18:27:27 +0100 Subject: [PATCH 194/593] Added possibility to use padding object with individual properties, fixes #195 --- src/scripts/charts/bar.js | 9 +++--- src/scripts/charts/line.js | 9 +++--- src/scripts/charts/pie.js | 4 +-- src/scripts/core.js | 40 +++++++++++++++++++----- test/spec/spec-core.js | 64 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 17 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 10f636d3..6cfcfb42 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -57,7 +57,7 @@ high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, - // Padding of the chart drawing area to the container element and labels + // 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} chartPadding: 5, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, @@ -88,6 +88,7 @@ function createChart(options) { var seriesGroups = [], normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), + normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding), highLow; // Create new svg element @@ -107,7 +108,7 @@ highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); - var chartRect = Chartist.createChartRect(this.svg, options); + var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, labelAxis; @@ -121,7 +122,7 @@ return projectedValue; }, { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length }, { @@ -172,7 +173,7 @@ return projectedValue; }, { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) }, { diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 3c602a97..821535f2 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -67,7 +67,7 @@ low: undefined, // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, - // Padding of the chart drawing area to the container element and labels + // 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} chartPadding: 5, // 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. fullWidth: false, @@ -95,12 +95,13 @@ */ function createChart(options) { var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), + normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - var chartRect = Chartist.createChartRect(this.svg, options); + var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var highLow = Chartist.getHighLow(normalizedData); // Overrides of high / low from settings @@ -132,7 +133,7 @@ return projectedValue; }, { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) }, { diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index b55e5cc0..31d9dcec 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -17,7 +17,7 @@ width: undefined, // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, - // Padding of the chart drawing area to the container element and labels + // 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} chartPadding: 5, // Override the class names that get used to generate the SVG structure of the chart classNames: { @@ -86,7 +86,7 @@ // Create SVG.js draw this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); // Calculate charting rect - chartRect = Chartist.createChartRect(this.svg, options, 0, 0); + chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); // Get biggest circle radius possible within chartRect radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); // Calculate total of all series to get reference value or use total reference from optional options diff --git a/src/scripts/core.js b/src/scripts/core.js index c3097ae5..2ff73a2d 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -343,6 +343,30 @@ var Chartist = { return array; }; + /** + * Converts a number into a padding object. + * + * @memberof Chartist.Core + * @param {Object|Number} padding + * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed + * @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. + */ + Chartist.normalizePadding = function(padding, fallback) { + fallback = fallback || 0; + + return typeof padding === 'number' ? { + top: padding, + right: padding, + bottom: padding, + left: padding + } : { + top: typeof padding.top === 'number' ? padding.top : fallback, + right: typeof padding.right === 'number' ? padding.right : fallback, + bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback, + left: typeof padding.left === 'number' ? padding.left : fallback + }; + }; + /** * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart * @@ -403,7 +427,7 @@ var Chartist = { * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); + return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0); }; /** @@ -550,19 +574,21 @@ var Chartist = { * @memberof Chartist.Core * @param {Object} svg The svg element for the chart * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ - Chartist.createChartRect = function (svg, options) { + Chartist.createChartRect = function (svg, options, fallbackPadding) { var yOffset = options.axisY ? options.axisY.offset || 0 : 0, xOffset = options.axisX ? options.axisX.offset || 0 : 0, w = Chartist.stripUnit(options.width) || svg.width(), - h = Chartist.stripUnit(options.height) || svg.height(); + h = Chartist.stripUnit(options.height) || svg.height(), + normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); return { - x1: options.chartPadding + yOffset, - y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset), - y2: options.chartPadding, + x1: normalizedPadding.left + yOffset, + y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom), + x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset), + y2: normalizedPadding.top, width: function () { return this.x2 - this.x1; }, diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 49644318..4b4ee2f4 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -142,4 +142,68 @@ describe('Chartist core', function() { ); }); }); + + describe('padding normalization tests', function () { + it('should normalize number padding', function() { + expect(Chartist.normalizePadding(10)).toEqual({ + top: 10, + right: 10, + bottom: 10, + left: 10 + }); + }); + + it('should normalize number padding when 0 is passed', function() { + expect(Chartist.normalizePadding(0)).toEqual({ + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + }); + + it('should normalize empty padding object with default fallback', function() { + expect(Chartist.normalizePadding({})).toEqual({ + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + }); + + it('should normalize empty padding object with specified fallback', function() { + expect(Chartist.normalizePadding({}, 10)).toEqual({ + top: 10, + right: 10, + bottom: 10, + left: 10 + }); + }); + + it('should normalize partial padding object with specified fallback', function() { + expect(Chartist.normalizePadding({ + top: 5, + left: 5 + }, 10)).toEqual({ + top: 5, + right: 10, + bottom: 10, + left: 5 + }); + }); + + it('should not modify complete padding object', function() { + expect(Chartist.normalizePadding({ + top: 5, + right: 5, + bottom: 5, + left: 5 + }, 10)).toEqual({ + top: 5, + right: 5, + bottom: 5, + left: 5 + }); + }); + }); }); From 455639edb56e8a124e514f175415ba6157e9567a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 27 Feb 2015 18:44:40 +0100 Subject: [PATCH 195/593] Version bump to 0.7.3 --- CHANGELOG.md | 7 + bower.json | 2 +- dist/chartist.js | 6004 +++++++++++++++++++------------------- dist/chartist.min.css | 6 - dist/chartist.min.js | 4 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- 7 files changed, 3021 insertions(+), 3006 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ede1cf..6f95c2b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v0.7.3 - 27 Feb 2015 +-------------------- +- Fixed bugs in the chart.update method +- Fixed rounding precision issues in order of magnitude calculation +- Fixed bug in Chartist.extend which caused merge problems from object properties into non-objects +- Added possibility to use chartPadding with a padding object that contains top, right, bottom and left properties + v0.7.2 - 12 Feb 2015 -------------------- - Added new line smoothing / interpolation module for configurable line smoothing diff --git a/bower.json b/bower.json index 036429e1..bd842412 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.7.2", + "version": "0.7.3", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index d0b4c0a5..45cf6dbf 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -1,12 +1,12 @@ (function (root, factory) { if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. + // AMD. Register as an anonymous module unless amdModuleId is set define([], function () { - return (root.returnExportsGlobal = factory()); + return (root['Chartist'] = factory()); }); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but - // only CommonJS-like enviroments that support module.exports, + // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(); } else { @@ -14,2445 +14,2865 @@ } }(this, function () { - /* Chartist.js 0.7.2 - * Copyright © 2015 Gion Kunz - * Free to use under the WTFPL license. - * http://www.wtfpl.net/ - */ +/* Chartist.js 0.7.3 + * Copyright © 2015 Gion Kunz + * Free to use under the WTFPL license. + * http://www.wtfpl.net/ + */ +/** + * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. + * + * @module Chartist.Core + */ +var Chartist = { + version: '0.7.3' +}; + +(function (window, document, Chartist) { + 'use strict'; + /** - * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. + * Helps to simplify functional style code * - * @module Chartist.Core + * @memberof Chartist.Core + * @param {*} n This exact value will be returned by the noop function + * @return {*} The same value that was provided to the n parameter */ - var Chartist = { - version: '0.7.1' + Chartist.noop = function (n) { + return n; }; - (function (window, document, Chartist) { - 'use strict'; - - /** - * Helps to simplify functional style code - * - * @memberof Chartist.Core - * @param {*} n This exact value will be returned by the noop function - * @return {*} The same value that was provided to the n parameter - */ - Chartist.noop = function (n) { - return n; - }; - - /** - * Generates a-z from a number 0 to 26 - * - * @memberof Chartist.Core - * @param {Number} n A number from 0 to 26 that will result in a letter a-z - * @return {String} A character from a-z based on the input number n - */ - Chartist.alphaNumerate = function (n) { - // Limit to a-z - return String.fromCharCode(97 + n % 26); - }; + /** + * Generates a-z from a number 0 to 26 + * + * @memberof Chartist.Core + * @param {Number} n A number from 0 to 26 that will result in a letter a-z + * @return {String} A character from a-z based on the input number n + */ + Chartist.alphaNumerate = function (n) { + // Limit to a-z + return String.fromCharCode(97 + n % 26); + }; - /** - * Simple recursive object extend - * - * @memberof Chartist.Core - * @param {Object} target Target object where the source will be merged into - * @param {Object...} sources This object (objects) will be merged into target and then target is returned - * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source - */ - Chartist.extend = function (target) { - target = target || {}; - - var sources = Array.prototype.slice.call(arguments, 1); - sources.forEach(function(source) { - for (var prop in source) { - if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) { - target[prop] = Chartist.extend(target[prop], source[prop]); - } else { - target[prop] = source[prop]; - } + /** + * Simple recursive object extend + * + * @memberof Chartist.Core + * @param {Object} target Target object where the source will be merged into + * @param {Object...} sources This object (objects) will be merged into target and then target is returned + * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source + */ + Chartist.extend = function (target) { + target = target || {}; + + var sources = Array.prototype.slice.call(arguments, 1); + sources.forEach(function(source) { + for (var prop in source) { + if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) { + target[prop] = Chartist.extend({}, target[prop], source[prop]); + } else { + target[prop] = source[prop]; } - }); - - return target; - }; + } + }); - /** - * Replaces all occurrences of subStr in str with newSubStr and returns a new string. - * - * @memberof Chartist.Core - * @param {String} str - * @param {String} subStr - * @param {String} newSubStr - * @return {String} - */ - Chartist.replaceAll = function(str, subStr, newSubStr) { - return str.replace(new RegExp(subStr, 'g'), newSubStr); - }; + return target; + }; - /** - * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {String|Number} value - * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel - */ - Chartist.stripUnit = function(value) { - if(typeof value === 'string') { - value = value.replace(/[^0-9\+-\.]/g, ''); - } + /** + * Replaces all occurrences of subStr in str with newSubStr and returns a new string. + * + * @memberof Chartist.Core + * @param {String} str + * @param {String} subStr + * @param {String} newSubStr + * @return {String} + */ + Chartist.replaceAll = function(str, subStr, newSubStr) { + return str.replace(new RegExp(subStr, 'g'), newSubStr); + }; - return +value; - }; + /** + * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {String|Number} value + * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel + */ + Chartist.stripUnit = function(value) { + if(typeof value === 'string') { + value = value.replace(/[^0-9\+-\.]/g, ''); + } - /** - * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {Number} value - * @param {String} unit - * @return {String} Returns the passed number value with unit. - */ - Chartist.ensureUnit = function(value, unit) { - if(typeof value === 'number') { - value = value + unit; - } + return +value; + }; - return value; - }; + /** + * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {Number} value + * @param {String} unit + * @return {String} Returns the passed number value with unit. + */ + Chartist.ensureUnit = function(value, unit) { + if(typeof value === 'number') { + value = value + unit; + } - /** - * This is a wrapper around document.querySelector that will return the query if it's already of type Node - * - * @memberof Chartist.Core - * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly - * @return {Node} - */ - Chartist.querySelector = function(query) { - return query instanceof Node ? query : document.querySelector(query); - }; + return value; + }; - /** - * Functional style helper to produce array with given length initialized with undefined values - * - * @memberof Chartist.Core - * @param length - * @return {Array} - */ - Chartist.times = function(length) { - return Array.apply(null, new Array(length)); - }; + /** + * This is a wrapper around document.querySelector that will return the query if it's already of type Node + * + * @memberof Chartist.Core + * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly + * @return {Node} + */ + Chartist.querySelector = function(query) { + return query instanceof Node ? query : document.querySelector(query); + }; - /** - * Sum helper to be used in reduce functions - * - * @memberof Chartist.Core - * @param previous - * @param current - * @return {*} - */ - Chartist.sum = function(previous, current) { - return previous + current; - }; + /** + * Functional style helper to produce array with given length initialized with undefined values + * + * @memberof Chartist.Core + * @param length + * @return {Array} + */ + Chartist.times = function(length) { + return Array.apply(null, new Array(length)); + }; - /** - * 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). - * - * @memberof Chartist.Core - * @param arr - * @param cb - * @return {Array} - */ - Chartist.serialMap = function(arr, cb) { - var result = [], - length = Math.max.apply(null, arr.map(function(e) { - return e.length; - })); - - Chartist.times(length).forEach(function(e, index) { - var args = arr.map(function(e) { - return e[index]; - }); + /** + * Sum helper to be used in reduce functions + * + * @memberof Chartist.Core + * @param previous + * @param current + * @return {*} + */ + Chartist.sum = function(previous, current) { + return previous + current; + }; - result[index] = cb.apply(null, args); + /** + * 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). + * + * @memberof Chartist.Core + * @param arr + * @param cb + * @return {Array} + */ + Chartist.serialMap = function(arr, cb) { + var result = [], + length = Math.max.apply(null, arr.map(function(e) { + return e.length; + })); + + Chartist.times(length).forEach(function(e, index) { + var args = arr.map(function(e) { + return e[index]; }); - return result; - }; + result[index] = cb.apply(null, args); + }); - /** - * A map with characters to escape for strings to be safely used as attribute values. - * - * @memberof Chartist.Core - * @type {Object} - */ - Chartist.escapingMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''' - }; + return result; + }; - /** - * 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. - * If called with null or undefined the function will return immediately with null or undefined. - * - * @memberof Chartist.Core - * @param {Number|String|Object} data - * @return {String} - */ - Chartist.serialize = function(data) { - if(data === null || data === undefined) { - return data; - } else if(typeof data === 'number') { - data = ''+data; - } else if(typeof data === 'object') { - data = JSON.stringify({data: data}); - } + /** + * 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. + * + * @memberof Chartist.Core + * @param {Number} value The value that should be rounded with precision + * @param {Number} [digits] The number of digits after decimal used to do the rounding + * @returns {number} Rounded value + */ + Chartist.roundWithPrecision = function(value, digits) { + var precision = Math.pow(10, digits || Chartist.precision); + return Math.round(value * precision) / precision; + }; - return Object.keys(Chartist.escapingMap).reduce(function(result, key) { - return Chartist.replaceAll(result, key, Chartist.escapingMap[key]); - }, data); - }; + /** + * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number. + * + * @memberof Chartist.Core + * @type {number} + */ + Chartist.precision = 8; - /** - * 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. - * - * @memberof Chartist.Core - * @param {String} data - * @return {String|Number|Object} - */ - Chartist.deserialize = function(data) { - if(typeof data !== 'string') { - return data; - } + /** + * A map with characters to escape for strings to be safely used as attribute values. + * + * @memberof Chartist.Core + * @type {Object} + */ + Chartist.escapingMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' + }; - data = Object.keys(Chartist.escapingMap).reduce(function(result, key) { - return Chartist.replaceAll(result, Chartist.escapingMap[key], key); - }, data); + /** + * 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. + * If called with null or undefined the function will return immediately with null or undefined. + * + * @memberof Chartist.Core + * @param {Number|String|Object} data + * @return {String} + */ + Chartist.serialize = function(data) { + if(data === null || data === undefined) { + return data; + } else if(typeof data === 'number') { + data = ''+data; + } else if(typeof data === 'object') { + data = JSON.stringify({data: data}); + } - try { - data = JSON.parse(data); - data = data.data !== undefined ? data.data : data; - } catch(e) {} + return Object.keys(Chartist.escapingMap).reduce(function(result, key) { + return Chartist.replaceAll(result, key, Chartist.escapingMap[key]); + }, data); + }; + /** + * 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. + * + * @memberof Chartist.Core + * @param {String} data + * @return {String|Number|Object} + */ + Chartist.deserialize = function(data) { + if(typeof data !== 'string') { return data; - }; + } - /** - * Create or reinitialize the SVG element for the chart - * - * @memberof Chartist.Core - * @param {Node} container The containing DOM Node object that will be used to plant the SVG element - * @param {String} width Set the width of the SVG element. Default is 100% - * @param {String} height Set the height of the SVG element. Default is 100% - * @param {String} className Specify a class to be added to the SVG element - * @return {Object} The created/reinitialized SVG element - */ - Chartist.createSvg = function (container, width, height, className) { - var svg; - - width = width || '100%'; - height = height || '100%'; - - // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it - // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ - Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttribute(Chartist.xmlNs.qualifiedName); - }).forEach(function removePreviousElement(svg) { - container.removeChild(svg); - }); + data = Object.keys(Chartist.escapingMap).reduce(function(result, key) { + return Chartist.replaceAll(result, Chartist.escapingMap[key], key); + }, data); - // Create svg object with width and height or use 100% as default - svg = new Chartist.Svg('svg').attr({ - width: width, - height: height - }).addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' - }); + try { + data = JSON.parse(data); + data = data.data !== undefined ? data.data : data; + } catch(e) {} - // Add the DOM node to our container - container.appendChild(svg._node); + return data; + }; - return svg; - }; + /** + * Create or reinitialize the SVG element for the chart + * + * @memberof Chartist.Core + * @param {Node} container The containing DOM Node object that will be used to plant the SVG element + * @param {String} width Set the width of the SVG element. Default is 100% + * @param {String} height Set the height of the SVG element. Default is 100% + * @param {String} className Specify a class to be added to the SVG element + * @return {Object} The created/reinitialized SVG element + */ + Chartist.createSvg = function (container, width, height, className) { + var svg; + + width = width || '100%'; + height = height || '100%'; + + // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it + // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ + Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { + return svg.getAttribute(Chartist.xmlNs.qualifiedName); + }).forEach(function removePreviousElement(svg) { + container.removeChild(svg); + }); + // Create svg object with width and height or use 100% as default + svg = new Chartist.Svg('svg').attr({ + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); - /** - * Reverses the series, labels and series data arrays. - * - * @memberof Chartist.Core - * @param data - */ - Chartist.reverseData = function(data) { - data.labels.reverse(); - data.series.reverse(); - for (var i = 0; i < data.series.length; i++) { - if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { - data.series[i].data.reverse(); - } else { - data.series[i].reverse(); - } - } - }; + // Add the DOM node to our container + container.appendChild(svg._node); - /** - * Convert data series into plain array - * - * @memberof Chartist.Core - * @param {Object} data The series object that contains the data to be visualized in the chart - * @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. - * @return {Array} A plain array that contains the data to be visualized in the chart - */ - Chartist.getDataArray = function (data, reverse) { - var array = [], - value, - localData; - - // If the data should be reversed but isn't we need to reverse it - // If it's reversed but it shouldn't we need to reverse it back - // That's required to handle data updates correctly and to reflect the responsive configurations - if(reverse && !data.reversed || !reverse && data.reversed) { - Chartist.reverseData(data); - data.reversed = !data.reversed; + return svg; + }; + + + /** + * Reverses the series, labels and series data arrays. + * + * @memberof Chartist.Core + * @param data + */ + Chartist.reverseData = function(data) { + data.labels.reverse(); + data.series.reverse(); + for (var i = 0; i < data.series.length; i++) { + if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { + data.series[i].data.reverse(); + } else { + data.series[i].reverse(); } + } + }; - for (var i = 0; i < data.series.length; i++) { - // If the series array contains an object with a data property we will use the property - // otherwise the value directly (array or number). - // We create a copy of the original data array with Array.prototype.push.apply - localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; - if(localData instanceof Array) { - array[i] = []; - Array.prototype.push.apply(array[i], localData); - } else { - array[i] = localData; - } + /** + * Convert data series into plain array + * + * @memberof Chartist.Core + * @param {Object} data The series object that contains the data to be visualized in the chart + * @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. + * @return {Array} A plain array that contains the data to be visualized in the chart + */ + Chartist.getDataArray = function (data, reverse) { + var array = [], + value, + localData; + + // If the data should be reversed but isn't we need to reverse it + // If it's reversed but it shouldn't we need to reverse it back + // That's required to handle data updates correctly and to reflect the responsive configurations + if(reverse && !data.reversed || !reverse && data.reversed) { + Chartist.reverseData(data); + data.reversed = !data.reversed; + } - // Convert object values to numbers - for (var j = 0; j < array[i].length; j++) { - value = array[i][j]; - value = value.value === 0 ? 0 : (value.value || value); - array[i][j] = +value; - } + for (var i = 0; i < data.series.length; i++) { + // If the series array contains an object with a data property we will use the property + // otherwise the value directly (array or number). + // We create a copy of the original data array with Array.prototype.push.apply + localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; + if(localData instanceof Array) { + array[i] = []; + Array.prototype.push.apply(array[i], localData); + } else { + array[i] = localData; + } + + // Convert object values to numbers + for (var j = 0; j < array[i].length; j++) { + value = array[i][j]; + value = value.value === 0 ? 0 : (value.value || value); + array[i][j] = +value; } + } + + return array; + }; - return array; + /** + * Converts a number into a padding object. + * + * @memberof Chartist.Core + * @param {Object|Number} padding + * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed + * @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. + */ + Chartist.normalizePadding = function(padding, fallback) { + fallback = fallback || 0; + + return typeof padding === 'number' ? { + top: padding, + right: padding, + bottom: padding, + left: padding + } : { + top: typeof padding.top === 'number' ? padding.top : fallback, + right: typeof padding.right === 'number' ? padding.right : fallback, + bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback, + left: typeof padding.left === 'number' ? padding.left : fallback }; + }; - /** - * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. - * @param {Number} length The length of the x-axis data array. - * @return {Array} The array that got updated with missing values. - */ - Chartist.normalizeDataArray = function (dataArray, length) { - for (var i = 0; i < dataArray.length; i++) { - if (dataArray[i].length === length) { - continue; - } + /** + * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart + * + * @memberof Chartist.Core + * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. + * @param {Number} length The length of the x-axis data array. + * @return {Array} The array that got updated with missing values. + */ + Chartist.normalizeDataArray = function (dataArray, length) { + for (var i = 0; i < dataArray.length; i++) { + if (dataArray[i].length === length) { + continue; + } - for (var j = dataArray[i].length; j < length; j++) { - dataArray[i][j] = 0; - } + for (var j = dataArray[i].length; j < length; j++) { + dataArray[i][j] = 0; } + } - return dataArray; - }; + return dataArray; + }; - Chartist.getMetaData = function(series, index) { - var value = series.data ? series.data[index] : series[index]; - return value ? Chartist.serialize(value.meta) : undefined; - }; + Chartist.getMetaData = function(series, index) { + var value = series.data ? series.data[index] : series[index]; + return value ? Chartist.serialize(value.meta) : undefined; + }; - /** - * Calculate the order of magnitude for the chart scale - * - * @memberof Chartist.Core - * @param {Number} value The value Range of the chart - * @return {Number} The order of magnitude - */ - Chartist.orderOfMagnitude = function (value) { - return Math.floor(Math.log(Math.abs(value)) / Math.LN10); - }; + /** + * Calculate the order of magnitude for the chart scale + * + * @memberof Chartist.Core + * @param {Number} value The value Range of the chart + * @return {Number} The order of magnitude + */ + Chartist.orderOfMagnitude = function (value) { + return Math.floor(Math.log(Math.abs(value)) / Math.LN10); + }; - /** - * Project a data length into screen coordinates (pixels) - * - * @memberof Chartist.Core - * @param {Object} axisLength The svg element for the chart - * @param {Number} length Single data value from a series array - * @param {Object} bounds All the values to set the bounds of the chart - * @return {Number} The projected data length in pixels - */ - Chartist.projectLength = function (axisLength, length, bounds) { - return length / bounds.range * axisLength; - }; + /** + * Project a data length into screen coordinates (pixels) + * + * @memberof Chartist.Core + * @param {Object} axisLength The svg element for the chart + * @param {Number} length Single data value from a series array + * @param {Object} bounds All the values to set the bounds of the chart + * @return {Number} The projected data length in pixels + */ + Chartist.projectLength = function (axisLength, length, bounds) { + return length / bounds.range * axisLength; + }; - /** - * Get the height of the area in the chart for the data series - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Number} The height of the area in the chart for the data series - */ - Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - options.axisX.offset, 0); - }; + /** + * Get the height of the area in the chart for the data series + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @return {Number} The height of the area in the chart for the data series + */ + Chartist.getAvailableHeight = function (svg, options) { + return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0); + }; - /** - * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart - * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. - */ - Chartist.getHighLow = function (dataArray) { - var i, - j, - highLow = { - high: -Number.MAX_VALUE, - low: Number.MAX_VALUE - }; + /** + * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. + * + * @memberof Chartist.Core + * @param {Array} dataArray The array that contains the data to be visualized in the chart + * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. + */ + Chartist.getHighLow = function (dataArray) { + var i, + j, + highLow = { + high: -Number.MAX_VALUE, + low: Number.MAX_VALUE + }; - for (i = 0; i < dataArray.length; i++) { - for (j = 0; j < dataArray[i].length; j++) { - if (dataArray[i][j] > highLow.high) { - highLow.high = dataArray[i][j]; - } + for (i = 0; i < dataArray.length; i++) { + for (j = 0; j < dataArray[i].length; j++) { + if (dataArray[i][j] > highLow.high) { + highLow.high = dataArray[i][j]; + } - if (dataArray[i][j] < highLow.low) { - highLow.low = dataArray[i][j]; - } + if (dataArray[i][j] < highLow.low) { + highLow.low = dataArray[i][j]; } } + } - return highLow; - }; + return highLow; + }; - /** - * Calculate and retrieve all the bounds for the chart and return them in one array - * - * @memberof Chartist.Core - * @param {Number} axisLength The length of the Axis used for - * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. - * @param {Number} scaleMinSpace The minimum projected length a step should result in - * @param {Number} referenceValue The reference value for the chart. - * @return {Object} All the values to set the bounds of the chart - */ - Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) { - var i, - newMin, - newMax, - bounds = { - high: highLow.high, - low: highLow.low - }; + /** + * Calculate and retrieve all the bounds for the chart and return them in one array + * + * @memberof Chartist.Core + * @param {Number} axisLength The length of the Axis used for + * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. + * @param {Number} scaleMinSpace The minimum projected length a step should result in + * @param {Number} referenceValue The reference value for the chart. + * @return {Object} All the values to set the bounds of the chart + */ + Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) { + var i, + newMin, + newMax, + bounds = { + high: highLow.high, + low: highLow.low + }; - // If high and low are the same because of misconfiguration or flat data (only the same value) we need - // to set the high or low to 0 depending on the polarity - if(bounds.high === bounds.low) { - // If both values are 0 we set high to 1 - if(bounds.low === 0) { - bounds.high = 1; - } else if(bounds.low < 0) { - // If we have the same negative value for the bounds we set bounds.high to 0 - bounds.high = 0; - } else { - // If we have the same positive value for the bounds we set bounds.low to 0 - bounds.low = 0; - } + // If high and low are the same because of misconfiguration or flat data (only the same value) we need + // to set the high or low to 0 depending on the polarity + if(bounds.high === bounds.low) { + // If both values are 0 we set high to 1 + if(bounds.low === 0) { + bounds.high = 1; + } else if(bounds.low < 0) { + // If we have the same negative value for the bounds we set bounds.high to 0 + bounds.high = 0; + } else { + // If we have the same positive value for the bounds we set bounds.low to 0 + bounds.low = 0; } + } - // Overrides of high / low based on reference value, it will make sure that the invisible reference value is - // used to generate the chart. This is useful when the chart always needs to contain the position of the - // invisible reference value in the view i.e. for bipolar scales. - if (referenceValue || referenceValue === 0) { - bounds.high = Math.max(referenceValue, bounds.high); - bounds.low = Math.min(referenceValue, bounds.low); - } + // Overrides of high / low based on reference value, it will make sure that the invisible reference value is + // used to generate the chart. This is useful when the chart always needs to contain the position of the + // invisible reference value in the view i.e. for bipolar scales. + if (referenceValue || referenceValue === 0) { + bounds.high = Math.max(referenceValue, bounds.high); + bounds.low = Math.min(referenceValue, bounds.low); + } - bounds.valueRange = bounds.high - bounds.low; - bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); - bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.range = bounds.max - bounds.min; - bounds.step = Math.pow(10, bounds.oom); - bounds.numberOfSteps = Math.round(bounds.range / bounds.step); - - // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace - // If we are already below the scaleMinSpace value we will scale up - var length = Chartist.projectLength(axisLength, bounds.step, bounds), - scaleUp = length < scaleMinSpace; - - while (true) { - if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { - bounds.step *= 2; - } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { - bounds.step /= 2; - } else { - break; - } + bounds.valueRange = bounds.high - bounds.low; + bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); + bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); + bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); + bounds.range = bounds.max - bounds.min; + bounds.step = Math.pow(10, bounds.oom); + bounds.numberOfSteps = Math.round(bounds.range / bounds.step); + + // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace + // If we are already below the scaleMinSpace value we will scale up + var length = Chartist.projectLength(axisLength, bounds.step, bounds), + scaleUp = length < scaleMinSpace; + + while (true) { + if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { + bounds.step /= 2; + } else { + break; } + } - // Narrow min and max based on new step - newMin = bounds.min; - newMax = bounds.max; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - if (i + bounds.step < bounds.low) { - newMin += bounds.step; - } - - if (i - bounds.step >= bounds.high) { - newMax -= bounds.step; - } + // Narrow min and max based on new step + newMin = bounds.min; + newMax = bounds.max; + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + if (i + bounds.step < bounds.low) { + newMin += bounds.step; } - bounds.min = newMin; - bounds.max = newMax; - bounds.range = bounds.max - bounds.min; - bounds.values = []; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - bounds.values.push(i); + if (i - bounds.step >= bounds.high) { + newMax -= bounds.step; } + } + bounds.min = newMin; + bounds.max = newMax; + bounds.range = bounds.max - bounds.min; - return bounds; - }; + bounds.values = []; + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + bounds.values.push(Chartist.roundWithPrecision(i)); + } - /** - * Calculate cartesian coordinates of polar coordinates - * - * @memberof Chartist.Core - * @param {Number} centerX X-axis coordinates of center point of circle segment - * @param {Number} centerY X-axis coordinates of center point of circle segment - * @param {Number} radius Radius of circle segment - * @param {Number} angleInDegrees Angle of circle segment in degrees - * @return {Number} Coordinates of point on circumference - */ - Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { - var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; + return bounds; + }; - return { - x: centerX + (radius * Math.cos(angleInRadians)), - y: centerY + (radius * Math.sin(angleInRadians)) - }; - }; - - /** - * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right - * - * @memberof Chartist.Core - * @param {Object} svg The svg element for the chart - * @param {Object} options The Object that contains all the optional values for the chart - * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements - */ - Chartist.createChartRect = function (svg, options) { - var yOffset = options.axisY ? options.axisY.offset || 0 : 0, - xOffset = options.axisX ? options.axisX.offset || 0 : 0, - w = Chartist.stripUnit(options.width) || svg.width(), - h = Chartist.stripUnit(options.height) || svg.height(); - - return { - x1: options.chartPadding + yOffset, - y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding), - x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset), - y2: options.chartPadding, - width: function () { - return this.x2 - this.x1; - }, - height: function () { - return this.y1 - this.y2; - } - }; - }; + /** + * Calculate cartesian coordinates of polar coordinates + * + * @memberof Chartist.Core + * @param {Number} centerX X-axis coordinates of center point of circle segment + * @param {Number} centerY X-axis coordinates of center point of circle segment + * @param {Number} radius Radius of circle segment + * @param {Number} angleInDegrees Angle of circle segment in degrees + * @return {Number} Coordinates of point on circumference + */ + Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { + var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; - /** - * Creates a grid line based on a projected value. - * - * @memberof Chartist.Core - * @param projectedValue - * @param index - * @param axis - * @param offset - * @param length - * @param group - * @param classes - * @param eventEmitter - */ - Chartist.createGrid = function(projectedValue, index, axis, offset, length, group, classes, eventEmitter) { - var positionalData = {}; - positionalData[axis.units.pos + '1'] = projectedValue.pos; - positionalData[axis.units.pos + '2'] = projectedValue.pos; - positionalData[axis.counterUnits.pos + '1'] = offset; - positionalData[axis.counterUnits.pos + '2'] = offset + length; - - var gridElement = group.elem('line', positionalData, classes.join(' ')); - - // Event for grid draw - eventEmitter.emit('draw', - Chartist.extend({ - type: 'grid', - axis: axis.units.pos, - index: index, - group: group, - element: gridElement - }, positionalData) - ); + return { + x: centerX + (radius * Math.cos(angleInRadians)), + y: centerY + (radius * Math.sin(angleInRadians)) }; + }; - /** - * Creates a label based on a projected value and an axis. - * - * @memberof Chartist.Core - * @param projectedValue - * @param index - * @param labels - * @param axis - * @param axisOffset - * @param labelOffset - * @param group - * @param classes - * @param useForeignObject - * @param eventEmitter - */ - Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { - var labelElement, - positionalData = {}; - positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; - positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; - positionalData[axis.units.len] = projectedValue.len; - positionalData[axis.counterUnits.len] = axisOffset; - - if(useForeignObject) { - var content = '' + labels[index] + ''; - labelElement = group.foreignObject(content, Chartist.extend({ - style: 'overflow: visible;' - }, positionalData)); - } else { - labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]); + /** + * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used + * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements + */ + Chartist.createChartRect = function (svg, options, fallbackPadding) { + var yOffset = options.axisY ? options.axisY.offset || 0 : 0, + xOffset = options.axisX ? options.axisX.offset || 0 : 0, + w = Chartist.stripUnit(options.width) || svg.width(), + h = Chartist.stripUnit(options.height) || svg.height(), + normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); + + return { + x1: normalizedPadding.left + yOffset, + y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom), + x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset), + y2: normalizedPadding.top, + width: function () { + return this.x2 - this.x1; + }, + height: function () { + return this.y1 - this.y2; } + }; + }; - eventEmitter.emit('draw', Chartist.extend({ - type: 'label', - axis: axis, + /** + * Creates a grid line based on a projected value. + * + * @memberof Chartist.Core + * @param projectedValue + * @param index + * @param axis + * @param offset + * @param length + * @param group + * @param classes + * @param eventEmitter + */ + Chartist.createGrid = function(projectedValue, index, axis, offset, length, group, classes, eventEmitter) { + var positionalData = {}; + positionalData[axis.units.pos + '1'] = projectedValue.pos; + positionalData[axis.units.pos + '2'] = projectedValue.pos; + positionalData[axis.counterUnits.pos + '1'] = offset; + positionalData[axis.counterUnits.pos + '2'] = offset + length; + + var gridElement = group.elem('line', positionalData, classes.join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', + Chartist.extend({ + type: 'grid', + axis: axis.units.pos, index: index, group: group, - element: labelElement, - text: labels[index] + element: gridElement + }, positionalData) + ); + }; + + /** + * Creates a label based on a projected value and an axis. + * + * @memberof Chartist.Core + * @param projectedValue + * @param index + * @param labels + * @param axis + * @param axisOffset + * @param labelOffset + * @param group + * @param classes + * @param useForeignObject + * @param eventEmitter + */ + Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + var labelElement, + positionalData = {}; + positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; + positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; + positionalData[axis.units.len] = projectedValue.len; + positionalData[axis.counterUnits.len] = axisOffset; + + if(useForeignObject) { + var content = '' + labels[index] + ''; + labelElement = group.foreignObject(content, Chartist.extend({ + style: 'overflow: visible;' }, positionalData)); - }; + } else { + labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]); + } - /** - * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect. - * - * @memberof Chartist.Core - * @param axis - * @param data - * @param chartRect - * @param gridGroup - * @param labelGroup - * @param useForeignObject - * @param options - * @param eventEmitter - */ - Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { - var axisOptions = options['axis' + axis.units.pos.toUpperCase()], - projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform), - labelValues = data.map(axisOptions.labelInterpolationFnc); - - projectedValues.forEach(function(projectedValue, index) { - // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!labelValues[index] && labelValues[index] !== 0) { - return; - } + eventEmitter.emit('draw', Chartist.extend({ + type: 'label', + axis: axis, + index: index, + group: group, + element: labelElement, + text: labels[index] + }, positionalData)); + }; - if(axisOptions.showGrid) { - Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ - options.classNames.grid, - options.classNames[axis.units.dir] - ], eventEmitter); - } + /** + * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect. + * + * @memberof Chartist.Core + * @param axis + * @param data + * @param chartRect + * @param gridGroup + * @param labelGroup + * @param useForeignObject + * @param options + * @param eventEmitter + */ + Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { + var axisOptions = options['axis' + axis.units.pos.toUpperCase()], + projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform), + labelValues = data.map(axisOptions.labelInterpolationFnc); + + projectedValues.forEach(function(projectedValue, index) { + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + if(!labelValues[index] && labelValues[index] !== 0) { + return; + } - if(axisOptions.showLabel) { - Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [ - options.classNames.label, - options.classNames[axis.units.dir] - ], useForeignObject, eventEmitter); - } - }); - }; + if(axisOptions.showGrid) { + Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ + options.classNames.grid, + options.classNames[axis.units.dir] + ], eventEmitter); + } - /** - * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches - * - * @memberof Chartist.Core - * @param {Object} options Options set by user - * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart - * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events - * @return {Object} The consolidated options object from the defaults, base and matching responsive options - */ - Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) { - var baseOptions = Chartist.extend({}, options), - currentOptions, - mediaQueryListeners = [], - i; - - function updateCurrentOptions() { - var previousOptions = currentOptions; - currentOptions = Chartist.extend({}, baseOptions); - - if (responsiveOptions) { - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); - if (mql.matches) { - currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]); - } - } - } + if(axisOptions.showLabel) { + Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [ + options.classNames.label, + options.classNames[axis.units.dir] + ], useForeignObject, eventEmitter); + } + }); + }; - if(eventEmitter) { - eventEmitter.emit('optionsChanged', { - previousOptions: previousOptions, - currentOptions: currentOptions - }); + /** + * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches + * + * @memberof Chartist.Core + * @param {Object} options Options set by user + * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart + * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events + * @return {Object} The consolidated options object from the defaults, base and matching responsive options + */ + Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) { + var baseOptions = Chartist.extend({}, options), + currentOptions, + mediaQueryListeners = [], + i; + + function updateCurrentOptions(preventChangedEvent) { + var previousOptions = currentOptions; + currentOptions = Chartist.extend({}, baseOptions); + + if (responsiveOptions) { + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + if (mql.matches) { + currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]); + } } } - function removeMediaQueryListeners() { - mediaQueryListeners.forEach(function(mql) { - mql.removeListener(updateCurrentOptions); + if(eventEmitter && !preventChangedEvent) { + eventEmitter.emit('optionsChanged', { + previousOptions: previousOptions, + currentOptions: currentOptions }); } + } - if (!window.matchMedia) { - throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; - } else if (responsiveOptions) { + function removeMediaQueryListeners() { + mediaQueryListeners.forEach(function(mql) { + mql.removeListener(updateCurrentOptions); + }); + } - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); - mql.addListener(updateCurrentOptions); - mediaQueryListeners.push(mql); - } + if (!window.matchMedia) { + throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; + } else if (responsiveOptions) { + + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + mql.addListener(updateCurrentOptions); + mediaQueryListeners.push(mql); } - // Execute initially so we get the correct options - updateCurrentOptions(); + } + // Execute initially so we get the correct options + updateCurrentOptions(true); - return { - get currentOptions() { - return Chartist.extend({}, currentOptions); - }, - removeMediaQueryListeners: removeMediaQueryListeners - }; + return { + get currentOptions() { + return Chartist.extend({}, currentOptions); + }, + removeMediaQueryListeners: removeMediaQueryListeners + }; + }; + +}(window, document, Chartist)); +;/** + * Chartist path interpolation functions. + * + * @module Chartist.Interpolation + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + Chartist.Interpolation = {}; + + /** + * This interpolation function does not smooth the path and the result is only containing lines and no curves. + * + * @memberof Chartist.Interpolation + * @return {Function} + */ + Chartist.Interpolation.none = function() { + return function cardinal(pathCoordinates) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + + for(var i = 3; i < pathCoordinates.length; i += 2) { + path.line(pathCoordinates[i - 1], pathCoordinates[i]); + } + + return path; + }; + }; + + /** + * 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. + * + * 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. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.simple({ + * divisor: 2 + * }) + * }); + * + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the simple interpolation factory function. + * @return {Function} + */ + Chartist.Interpolation.simple = function(options) { + var defaultOptions = { + divisor: 2 + }; + options = Chartist.extend({}, defaultOptions, options); + + var d = 1 / Math.max(1, options.divisor); + + return function simple(pathCoordinates) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + + for(var i = 2; i < pathCoordinates.length; i += 2) { + var prevX = pathCoordinates[i - 2], + prevY = pathCoordinates[i - 1], + currX = pathCoordinates[i], + currY = pathCoordinates[i + 1], + length = (currX - prevX) * d; + + path.curve( + prevX + length, + prevY, + currX - length, + currY, + currX, + currY + ); + } + + return path; + }; + }; + + /** + * 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. + * + * 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`. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 1 + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the cardinal factory function. + * @return {Function} + */ + Chartist.Interpolation.cardinal = function(options) { + var defaultOptions = { + tension: 1 }; - //http://schepers.cc/getting-to-the-point - Chartist.catmullRom2bezier = function (crp, z) { - var d = []; - for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + options = Chartist.extend({}, defaultOptions, options); + + var t = Math.min(1, Math.max(0, options.tension)), + c = 1 - t; + + return function cardinal(pathCoordinates) { + // If less than two points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return Chartist.Interpolation.none()(pathCoordinates); + } + + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]), + z; + + for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { var p = [ - {x: +crp[i - 2], y: +crp[i - 1]}, - {x: +crp[i], y: +crp[i + 1]}, - {x: +crp[i + 2], y: +crp[i + 3]}, - {x: +crp[i + 4], y: +crp[i + 5]} + {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, + {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, + {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, + {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} ]; if (z) { if (!i) { - p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; } else if (iLen - 4 === i) { - p[3] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; } else if (iLen - 2 === i) { - p[2] = {x: +crp[0], y: +crp[1]}; - p[3] = {x: +crp[2], y: +crp[3]}; + p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; } } else { if (iLen - 4 === i) { p[3] = p[2]; } else if (!i) { - p[0] = {x: +crp[i], y: +crp[i + 1]}; + p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; } } - d.push( - [ - (-p[0].x + 6 * p[1].x + p[2].x) / 6, - (-p[0].y + 6 * p[1].y + p[2].y) / 6, - (p[1].x + 6 * p[2].x - p[3].x) / 6, - (p[1].y + 6 * p[2].y - p[3].y) / 6, - p[2].x, - p[2].y - ] + + path.curve( + (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), + (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), + (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), + (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), + p[2].x, + p[2].y ); } - return d; + return path; }; + }; - }(window, document, Chartist)); - ;/** - * Chartist path interpolation functions. - * - * @module Chartist.Interpolation - */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; +}(window, document, Chartist)); +;/** + * A very basic event module that helps to generate and catch events. + * + * @module Chartist.Event + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; - Chartist.Interpolation = {}; + Chartist.EventEmitter = function () { + var handlers = []; /** - * This interpolation function does not smooth the path and the result is only containing lines and no curves. + * Add an event handler for a specific event * - * @memberof Chartist.Interpolation - * @return {Function} + * @memberof Chartist.Event + * @param {String} event The event name + * @param {Function} handler A event handler function */ - Chartist.Interpolation.none = function() { - return function cardinal(pathCoordinates) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + function addEventHandler(event, handler) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + } - for(var i = 3; i < pathCoordinates.length; i += 2) { - path.line(pathCoordinates[i - 1], pathCoordinates[i]); + /** + * Remove an event handler of a specific event name or remove all event handlers for a specific event. + * + * @memberof Chartist.Event + * @param {String} event The event name where a specific or all handlers should be removed + * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. + */ + function removeEventHandler(event, handler) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + // If handler is set we will look for a specific handler and only remove this + if(handler) { + handlers[event].splice(handlers[event].indexOf(handler), 1); + if(handlers[event].length === 0) { + delete handlers[event]; + } + } else { + // If no handler is specified we remove all handlers for this event + delete handlers[event]; } - - return path; - }; - }; + } + } /** - * 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. - * - * 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. - * - * 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. - * - * @example - * var chart = new Chartist.Line('.ct-chart', { - * labels: [1, 2, 3, 4, 5], - * series: [[1, 2, 8, 1, 7]] - * }, { - * lineSmooth: Chartist.Interpolation.simple({ - * divisor: 2 - * }) - * }); - * + * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. * - * @memberof Chartist.Interpolation - * @param {Object} options The options of the simple interpolation factory function. - * @return {Function} + * @memberof Chartist.Event + * @param {String} event The event name that should be triggered + * @param {*} data Arbitrary data that will be passed to the event handler callback functions */ - Chartist.Interpolation.simple = function(options) { - var defaultOptions = { - divisor: 2 - }; - options = Chartist.extend({}, defaultOptions, options); - - var d = 1 / Math.max(1, options.divisor); - - return function simple(pathCoordinates) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); - - for(var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2], - prevY = pathCoordinates[i - 1], - currX = pathCoordinates[i], - currY = pathCoordinates[i + 1], - length = (currX - prevX) * d; - - path.curve( - prevX + length, - prevY, - currX - length, - currY, - currX, - currY - ); - } + function emit(event, data) { + // Only do something if there are event handlers with this name existing + if(handlers[event]) { + handlers[event].forEach(function(handler) { + handler(data); + }); + } - return path; - }; + // Emit event to star event handlers + if(handlers['*']) { + handlers['*'].forEach(function(starHandler) { + starHandler(event, data); + }); + } + } + + return { + addEventHandler: addEventHandler, + removeEventHandler: removeEventHandler, + emit: emit }; + }; - /** - * 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. - * - * 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`. - * - * 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. +}(window, document, Chartist)); +;/** + * This module provides some basic prototype inheritance utilities. + * + * @module Chartist.Class + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + function listToArray(list) { + var arr = []; + if (list.length) { + for (var i = 0; i < list.length; i++) { + arr.push(list[i]); + } + } + return arr; + } + + /** + * Method to extend from current prototype. + * + * @memberof Chartist.Class + * @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. + * @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. + * @return {Function} Constructor function of the new class + * + * @example + * var Fruit = Class.extend({ + * color: undefined, + * sugar: undefined, + * + * constructor: function(color, sugar) { + * this.color = color; + * this.sugar = sugar; + * }, * - * @example - * var chart = new Chartist.Line('.ct-chart', { - * labels: [1, 2, 3, 4, 5], - * series: [[1, 2, 8, 1, 7]] - * }, { - * lineSmooth: Chartist.Interpolation.cardinal({ - * tension: 1 - * }) + * eat: function() { + * this.sugar = 0; + * return this; + * } * }); + * + * var Banana = Fruit.extend({ + * length: undefined, * - * @memberof Chartist.Interpolation - * @param {Object} options The options of the cardinal factory function. - * @return {Function} - */ - Chartist.Interpolation.cardinal = function(options) { - var defaultOptions = { - tension: 1 - }; - - options = Chartist.extend({}, defaultOptions, options); - - var t = Math.min(1, Math.max(0, options.tension)), - c = 1 - t; + * constructor: function(length, sugar) { + * Banana.super.constructor.call(this, 'Yellow', sugar); + * this.length = length; + * } + * }); + * + * var banana = new Banana(20, 40); + * console.log('banana instanceof Fruit', banana instanceof Fruit); + * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); + * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); + * console.log(banana.sugar); + * console.log(banana.eat().sugar); + * console.log(banana.color); + */ + function extend(properties, superProtoOverride) { + var superProto = superProtoOverride || this.prototype || Chartist.Class; + var proto = Object.create(superProto); - return function cardinal(pathCoordinates) { - // If less than two points we need to fallback to no smoothing - if(pathCoordinates.length <= 4) { - return Chartist.Interpolation.none()(pathCoordinates); - } + Chartist.Class.cloneDefinitions(proto, properties); - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]), - z; - - for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { - var p = [ - {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, - {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, - {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, - {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} - ]; - if (z) { - if (!i) { - p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; - } else if (iLen - 4 === i) { - p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; - } else if (iLen - 2 === i) { - p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; - p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; - } - } else { - if (iLen - 4 === i) { - p[3] = p[2]; - } else if (!i) { - p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; - } - } + var constr = function() { + var fn = proto.constructor || function () {}, + instance; - path.curve( - (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), - (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), - (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), - (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), - p[2].x, - p[2].y - ); - } + // If this is linked to the Chartist namespace the constructor was not called with new + // To provide a fallback we will instantiate here and return the instance + instance = this === Chartist ? Object.create(proto) : this; + fn.apply(instance, Array.prototype.slice.call(arguments, 0)); - return path; - }; + // If this constructor was not called with new we need to return the instance + // This will not harm when the constructor has been called with new as the returned value is ignored + return instance; }; - }(window, document, Chartist)); - ;/** - * A very basic event module that helps to generate and catch events. - * - * @module Chartist.Event - */ - /* global Chartist */ - (function (window, document, Chartist) { - 'use strict'; - - Chartist.EventEmitter = function () { - var handlers = []; - - /** - * Add an event handler for a specific event - * - * @memberof Chartist.Event - * @param {String} event The event name - * @param {Function} handler A event handler function - */ - function addEventHandler(event, handler) { - handlers[event] = handlers[event] || []; - handlers[event].push(handler); - } + constr.prototype = proto; + constr.super = superProto; + constr.extend = this.extend; - /** - * Remove an event handler of a specific event name or remove all event handlers for a specific event. - * - * @memberof Chartist.Event - * @param {String} event The event name where a specific or all handlers should be removed - * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. - */ - function removeEventHandler(event, handler) { - // Only do something if there are event handlers with this name existing - if(handlers[event]) { - // If handler is set we will look for a specific handler and only remove this - if(handler) { - handlers[event].splice(handlers[event].indexOf(handler), 1); - if(handlers[event].length === 0) { - delete handlers[event]; - } - } else { - // If no handler is specified we remove all handlers for this event - delete handlers[event]; - } - } - } + return constr; + } - /** - * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. - * - * @memberof Chartist.Event - * @param {String} event The event name that should be triggered - * @param {*} data Arbitrary data that will be passed to the event handler callback functions - */ - function emit(event, data) { - // Only do something if there are event handlers with this name existing - if(handlers[event]) { - handlers[event].forEach(function(handler) { - handler(data); - }); - } + // Variable argument list clones args > 0 into args[0] and retruns modified args[0] + function cloneDefinitions() { + var args = listToArray(arguments); + var target = args[0]; + + args.splice(1, args.length - 1).forEach(function (source) { + Object.getOwnPropertyNames(source).forEach(function (propName) { + // If this property already exist in target we delete it first + delete target[propName]; + // Define the property with the descriptor from source + Object.defineProperty(target, propName, + Object.getOwnPropertyDescriptor(source, propName)); + }); + }); - // Emit event to star event handlers - if(handlers['*']) { - handlers['*'].forEach(function(starHandler) { - starHandler(event, data); - }); - } - } + return target; + } - return { - addEventHandler: addEventHandler, - removeEventHandler: removeEventHandler, - emit: emit - }; - }; + Chartist.Class = { + extend: extend, + cloneDefinitions: cloneDefinitions + }; - }(window, document, Chartist)); - ;/** - * This module provides some basic prototype inheritance utilities. +}(window, document, Chartist)); +;/** + * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. + * + * @module Chartist.Base + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container + /** + * Updates the chart which currently does a full reconstruction of the SVG DOM * - * @module Chartist.Class + * @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. + * @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. + * @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 + * @memberof Chartist.Base */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; + function update(data, options, override) { + if(data) { + this.data = data; + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'update', + data: this.data + }); + } - function listToArray(list) { - var arr = []; - if (list.length) { - for (var i = 0; i < list.length; i++) { - arr.push(list[i]); - } + if(options) { + this.options = Chartist.extend({}, override ? this.options : this.defaultOptions, options); + + // If chartist was not initialized yet, we just set the options and leave the rest to the initialization + // Otherwise we re-create the optionsProvider at this point + if(!this.initializeTimeoutId) { + this.optionsProvider.removeMediaQueryListeners(); + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); } - return arr; } - /** - * Method to extend from current prototype. - * - * @memberof Chartist.Class - * @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. - * @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. - * @return {Function} Constructor function of the new class - * - * @example - * var Fruit = Class.extend({ - * color: undefined, - * sugar: undefined, - * - * constructor: function(color, sugar) { - * this.color = color; - * this.sugar = sugar; - * }, - * - * eat: function() { - * this.sugar = 0; - * return this; - * } - * }); - * - * var Banana = Fruit.extend({ - * length: undefined, - * - * constructor: function(length, sugar) { - * Banana.super.constructor.call(this, 'Yellow', sugar); - * this.length = length; - * } - * }); - * - * var banana = new Banana(20, 40); - * console.log('banana instanceof Fruit', banana instanceof Fruit); - * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); - * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); - * console.log(banana.sugar); - * console.log(banana.eat().sugar); - * console.log(banana.color); - */ - function extend(properties, superProtoOverride) { - var superProto = superProtoOverride || this.prototype || Chartist.Class; - var proto = Object.create(superProto); - - Chartist.Class.cloneDefinitions(proto, properties); + // Only re-created the chart if it has been initialized yet + if(!this.initializeTimeoutId) { + this.createChart(this.optionsProvider.currentOptions); + } - var constr = function() { - var fn = proto.constructor || function () {}, - instance; + // Return a reference to the chart object to chain up calls + return this; + } - // If this is linked to the Chartist namespace the constructor was not called with new - // To provide a fallback we will instantiate here and return the instance - instance = this === Chartist ? Object.create(proto) : this; - fn.apply(instance, Array.prototype.slice.call(arguments, 0)); + /** + * 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. + * + * @memberof Chartist.Base + */ + function detach() { + window.removeEventListener('resize', this.resizeListener); + this.optionsProvider.removeMediaQueryListeners(); + return this; + } - // If this constructor was not called with new we need to return the instance - // This will not harm when the constructor has been called with new as the returned value is ignored - return instance; - }; + /** + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. + * + * @memberof Chartist.Base + * @param {String} event Name of the event. Check the examples for supported events. + * @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. + */ + function on(event, handler) { + this.eventEmitter.addEventHandler(event, handler); + return this; + } - constr.prototype = proto; - constr.super = superProto; - constr.extend = this.extend; + /** + * 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. + * + * @memberof Chartist.Base + * @param {String} event Name of the event for which a handler should be removed + * @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. + */ + function off(event, handler) { + this.eventEmitter.removeEventHandler(event, handler); + return this; + } - return constr; + function initialize() { + // Add window resize listener that re-creates the chart + window.addEventListener('resize', this.resizeListener); + + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + // Register options change listener that will trigger a chart update + this.eventEmitter.addEventHandler('optionsChanged', function() { + this.update(); + }.bind(this)); + + // Before the first chart creation we need to register us with all plugins that are configured + // Initialize all relevant plugins with our chart object and the plugin options specified in the config + if(this.options.plugins) { + this.options.plugins.forEach(function(plugin) { + if(plugin instanceof Array) { + plugin[0](this, plugin[1]); + } else { + plugin(this); + } + }.bind(this)); } - // Variable argument list clones args > 0 into args[0] and retruns modified args[0] - function cloneDefinitions() { - var args = listToArray(arguments); - var target = args[0]; - - args.splice(1, args.length - 1).forEach(function (source) { - Object.getOwnPropertyNames(source).forEach(function (propName) { - // If this property already exist in target we delete it first - delete target[propName]; - // Define the property with the descriptor from source - Object.defineProperty(target, propName, - Object.getOwnPropertyDescriptor(source, propName)); - }); - }); + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'initial', + data: this.data + }); - return target; - } + // Create the first chart + this.createChart(this.optionsProvider.currentOptions); - Chartist.Class = { - extend: extend, - cloneDefinitions: cloneDefinitions - }; + // As chart is initialized from the event loop now we can reset our timeout reference + // This is important if the chart gets initialized on the same element twice + this.initializeTimeoutId = undefined; + } - }(window, document, Chartist)); - ;/** - * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. + /** + * Constructor of chart base class. * - * @module Chartist.Base + * @param query + * @param data + * @param defaultOptions + * @param options + * @param responsiveOptions + * @constructor */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. - // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not - // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. - // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html - // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj - // The problem is with the label offsets that can't be converted into percentage and affecting the chart container - /** - * Updates the chart which currently does a full reconstruction of the SVG DOM - * - * @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. - * @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. - * @param {Boolean} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already. - * @memberof Chartist.Base - */ - function update(data, options, extendObjects) { - if(data) { - this.data = data; - // Event for data transformation that allows to manipulate the data before it gets rendered in the charts - this.eventEmitter.emit('data', { - type: 'update', - data: this.data - }); - } - - if(options) { - this.options = Chartist.extend({}, extendObjects ? this.options : {}, options); - - // If chartist was not initialized yet, we just set the options and leave the rest to the initialization - if(!this.initializeTimeoutId) { - this.optionsProvider.removeMediaQueryListeners(); - this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + function Base(query, data, defaultOptions, options, responsiveOptions) { + this.container = Chartist.querySelector(query); + this.data = data; + this.defaultOptions = defaultOptions; + this.options = options; + this.responsiveOptions = responsiveOptions; + this.eventEmitter = Chartist.EventEmitter(); + this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); + this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); + this.resizeListener = function resizeListener(){ + this.update(); + }.bind(this); + + if(this.container) { + // If chartist was already initialized in this container we are detaching all event listeners first + if(this.container.__chartist__) { + if(this.container.__chartist__.initializeTimeoutId) { + // If the initializeTimeoutId is still set we can safely assume that the initialization function has not + // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach + window.clearTimeout(this.container.__chartist__.initializeTimeoutId); + } else { + // The timeout reference has already been reset which means we need to detach the old chart first + this.container.__chartist__.detach(); } } - // Only re-created the chart if it has been initialized yet - if(!this.initializeTimeoutId) { - this.createChart(this.optionsProvider.currentOptions); - } - - // Return a reference to the chart object to chain up calls - return this; + this.container.__chartist__ = this; } - /** - * 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. - * - * @memberof Chartist.Base - */ - function detach() { - window.removeEventListener('resize', this.resizeListener); - this.optionsProvider.removeMediaQueryListeners(); - return this; - } - - /** - * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. - * - * @memberof Chartist.Base - * @param {String} event Name of the event. Check the examples for supported events. - * @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. - */ - function on(event, handler) { - this.eventEmitter.addEventHandler(event, handler); - return this; - } - - /** - * 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. - * - * @memberof Chartist.Base - * @param {String} event Name of the event for which a handler should be removed - * @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. - */ - function off(event, handler) { - this.eventEmitter.removeEventHandler(event, handler); - return this; - } - - function initialize() { - // Add window resize listener that re-creates the chart - window.addEventListener('resize', this.resizeListener); + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + this.initializeTimeoutId = setTimeout(initialize.bind(this), 0); + } - // Obtain current options based on matching media queries (if responsive options are given) - // This will also register a listener that is re-creating the chart based on media changes - this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); - // Register options change listener that will trigger a chart update - this.eventEmitter.addEventHandler('optionsChanged', function() { - this.update(); - }.bind(this)); + // Creating the chart base class + Chartist.Base = Chartist.Class.extend({ + constructor: Base, + optionsProvider: undefined, + container: undefined, + svg: undefined, + eventEmitter: undefined, + createChart: function() { + throw new Error('Base chart type can\'t be instantiated!'); + }, + update: update, + detach: detach, + on: on, + off: off, + version: Chartist.version, + supportsForeignObject: false + }); + +}(window, document, Chartist)); +;/** + * Chartist SVG module for simple SVG DOM abstraction + * + * @module Chartist.Svg + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + var svgNs = 'http://www.w3.org/2000/svg', + xmlNs = 'http://www.w3.org/2000/xmlns/', + xhtmlNs = 'http://www.w3.org/1999/xhtml'; + + Chartist.xmlNs = { + qualifiedName: 'xmlns:ct', + prefix: 'ct', + uri: 'http://gionkunz.github.com/chartist-js/ct' + }; - // Before the first chart creation we need to register us with all plugins that are configured - // Initialize all relevant plugins with our chart object and the plugin options specified in the config - if(this.options.plugins) { - this.options.plugins.forEach(function(plugin) { - if(plugin instanceof Array) { - plugin[0](this, plugin[1]); - } else { - plugin(this); - } - }.bind(this)); + /** + * 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. + * + * @memberof Chartist.Svg + * @constructor + * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg + * @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. + * @param {String} className This class or class list will be added to the SVG element + * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child + * @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 + */ + function Svg(name, attributes, className, parent, insertFirst) { + // If Svg is getting called with an SVG element we just return the wrapper + if(name instanceof SVGElement) { + this._node = name; + } else { + this._node = document.createElementNS(svgNs, name); + + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); } - // Event for data transformation that allows to manipulate the data before it gets rendered in the charts - this.eventEmitter.emit('data', { - type: 'initial', - data: this.data - }); - - // Create the first chart - this.createChart(this.optionsProvider.currentOptions); + if(attributes) { + this.attr(attributes); + } - // As chart is initialized from the event loop now we can reset our timeout reference - // This is important if the chart gets initialized on the same element twice - this.initializeTimeoutId = undefined; - } + if(className) { + this.addClass(className); + } - /** - * Constructor of chart base class. - * - * @param query - * @param data - * @param options - * @param responsiveOptions - * @constructor - */ - function Base(query, data, options, responsiveOptions) { - this.container = Chartist.querySelector(query); - this.data = data; - this.options = options; - this.responsiveOptions = responsiveOptions; - this.eventEmitter = Chartist.EventEmitter(); - this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); - this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); - this.resizeListener = function resizeListener(){ - this.update(); - }.bind(this); - - if(this.container) { - // If chartist was already initialized in this container we are detaching all event listeners first - if(this.container.__chartist__) { - if(this.container.__chartist__.initializeTimeoutId) { - // If the initializeTimeoutId is still set we can safely assume that the initialization function has not - // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach - window.clearTimeout(this.container.__chartist__.initializeTimeoutId); - } else { - // The timeout reference has already been reset which means we need to detach the old chart first - this.container.__chartist__.detach(); - } + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); } - - this.container.__chartist__ = this; } - - // Using event loop for first draw to make it possible to register event listeners in the same call stack where - // the chart was created. - this.initializeTimeoutId = setTimeout(initialize.bind(this), 0); } + } - // Creating the chart base class - Chartist.Base = Chartist.Class.extend({ - constructor: Base, - optionsProvider: undefined, - container: undefined, - svg: undefined, - eventEmitter: undefined, - createChart: function() { - throw new Error('Base chart type can\'t be instantiated!'); - }, - update: update, - detach: detach, - on: on, - off: off, - version: Chartist.version, - supportsForeignObject: false - }); - - }(window, document, Chartist)); - ;/** - * Chartist SVG module for simple SVG DOM abstraction + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. * - * @module Chartist.Svg + * @memberof Chartist.Svg + * @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. + * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @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. */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; - - Chartist.xmlNs = { - qualifiedName: 'xmlns:ct', - prefix: 'ct', - uri: 'http://gionkunz.github.com/chartist-js/ct' - }; - - /** - * 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. - * - * @memberof Chartist.Svg - * @constructor - * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg - * @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. - * @param {String} className This class or class list will be added to the SVG element - * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child - * @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 - */ - function Svg(name, attributes, className, parent, insertFirst) { - // If Svg is getting called with an SVG element we just return the wrapper - if(name instanceof SVGElement) { - this._node = name; + function attr(attributes, ns) { + if(typeof attributes === 'string') { + if(ns) { + return this._node.getAttributeNS(ns, attributes); } else { - this._node = document.createElementNS(svgNs, name); - - // If this is an SVG element created then custom namespace - if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); - } - - if(attributes) { - this.attr(attributes); - } - - if(className) { - this.addClass(className); - } - - if(parent) { - if (insertFirst && parent._node.firstChild) { - parent._node.insertBefore(this._node, parent._node.firstChild); - } else { - parent._node.appendChild(this._node); - } - } + return this._node.getAttribute(attributes); } } - /** - * Set attributes on the current SVG element of the wrapper you're currently working on. - * - * @memberof Chartist.Svg - * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. - * @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. - */ - function attr(attributes, ns) { - if(typeof attributes === 'string') { - if(ns) { - return this._node.getAttributeNS(ns, attributes); - } else { - return this._node.getAttribute(attributes); - } + Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; } - Object.keys(attributes).forEach(function(key) { - // If the attribute value is undefined we can skip this one - if(attributes[key] === undefined) { - return; - } + if(ns) { + this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + } else { + this._node.setAttribute(key, attributes[key]); + } + }.bind(this)); - if(ns) { - this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); - } else { - this._node.setAttribute(key, attributes[key]); - } - }.bind(this)); + return this; + } - return this; - } + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Chartist.Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data + */ + function elem(name, attributes, className, insertFirst) { + return new Chartist.Svg(name, attributes, className, this, insertFirst); + } - /** - * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. - * - * @memberof Chartist.Svg - * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @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 - * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data - */ - function elem(name, attributes, className, insertFirst) { - return new Chartist.Svg(name, attributes, className, this, insertFirst); - } + /** + * Returns the parent Chartist.SVG wrapper object + * + * @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. + */ + function parent() { + return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; + } - /** - * Returns the parent Chartist.SVG wrapper object - * - * @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. - */ - function parent() { - return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; + /** + * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. + * + * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element + */ + function root() { + var node = this._node; + while(node.nodeName !== 'svg') { + node = node.parentNode; } + return new Chartist.Svg(node); + } - /** - * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. - * - * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element - */ - function root() { - var node = this._node; - while(node.nodeName !== 'svg') { - node = node.parentNode; - } - return new Chartist.Svg(node); - } + /** + * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found + */ + function querySelector(selector) { + var foundNode = this._node.querySelector(selector); + return foundNode ? new Chartist.Svg(foundNode) : null; + } - /** - * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. - * - * @param {String} selector A CSS selector that is used to query for child SVG elements - * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found - */ - function querySelector(selector) { - var foundNode = this._node.querySelector(selector); - return foundNode ? new Chartist.Svg(foundNode) : null; - } + /** + * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. + * + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found + */ + function querySelectorAll(selector) { + var foundNodes = this._node.querySelectorAll(selector); + return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; + } - /** - * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. - * - * @param {String} selector A CSS selector that is used to query for child SVG elements - * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found - */ - function querySelectorAll(selector) { - var foundNodes = this._node.querySelectorAll(selector); - return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; + /** + * 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. + * + * @memberof Chartist.Svg + * @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 + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element + */ + function foreignObject(content, attributes, className, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; } - /** - * 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. - * - * @memberof Chartist.Svg - * @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 - * @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. - * @param {String} [className] This class or class list will be added to the SVG element - * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child - * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element - */ - function foreignObject(content, attributes, className, insertFirst) { - // If content is string then we convert it to DOM - // TODO: Handle case where content is not a string nor a DOM Node - if(typeof content === 'string') { - var container = document.createElement('div'); - container.innerHTML = content; - content = container.firstChild; - } + // Adding namespace to content element + content.setAttribute('xmlns', xhtmlNs); - // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = this.elem('foreignObject', attributes, className, insertFirst); - // Creating the foreignObject without required extension attribute (as described here - // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = this.elem('foreignObject', attributes, className, insertFirst); + // Add content to foreignObjectElement + fnObj._node.appendChild(content); - // Add content to foreignObjectElement - fnObj._node.appendChild(content); + return fnObj; + } - return fnObj; - } + /** + * This method adds a new text element to the current Chartist.Svg wrapper. + * + * @memberof Chartist.Svg + * @param {String} t The text that should be added to the text element that is created + * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element + */ + function text(t) { + this._node.appendChild(document.createTextNode(t)); + return this; + } - /** - * This method adds a new text element to the current Chartist.Svg wrapper. - * - * @memberof Chartist.Svg - * @param {String} t The text that should be added to the text element that is created - * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element - */ - function text(t) { - this._node.appendChild(document.createTextNode(t)); - return this; + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Chartist.Svg + * @return {Chartist.Svg} The same wrapper object that got emptied + */ + function empty() { + while (this._node.firstChild) { + this._node.removeChild(this._node.firstChild); } - /** - * This method will clear all child nodes of the current wrapper object. - * - * @memberof Chartist.Svg - * @return {Chartist.Svg} The same wrapper object that got emptied - */ - function empty() { - while (this._node.firstChild) { - this._node.removeChild(this._node.firstChild); - } + return this; + } - return this; - } + /** + * 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. + * + * @memberof Chartist.Svg + * @return {Chartist.Svg} The parent wrapper object of the element that got removed + */ + function remove() { + this._node.parentNode.removeChild(this._node); + return this.parent(); + } - /** - * 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. - * - * @memberof Chartist.Svg - * @return {Chartist.Svg} The parent wrapper object of the element that got removed - */ - function remove() { - this._node.parentNode.removeChild(this._node); - return this.parent(); - } + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Chartist.Svg + * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object + * @return {Chartist.Svg} The wrapper of the new element + */ + function replace(newElement) { + this._node.parentNode.replaceChild(newElement._node, this._node); + return newElement; + } - /** - * This method will replace the element with a new element that can be created outside of the current DOM. - * - * @memberof Chartist.Svg - * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object - * @return {Chartist.Svg} The wrapper of the new element - */ - function replace(newElement) { - this._node.parentNode.replaceChild(newElement._node, this._node); - return newElement; + /** + * This method will append an element to the current element as a child. + * + * @memberof Chartist.Svg + * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @return {Chartist.Svg} The wrapper of the appended object + */ + function append(element, insertFirst) { + if(insertFirst && this._node.firstChild) { + this._node.insertBefore(element._node, this._node.firstChild); + } else { + this._node.appendChild(element._node); } - /** - * This method will append an element to the current element as a child. - * - * @memberof Chartist.Svg - * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child - * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child - * @return {Chartist.Svg} The wrapper of the appended object - */ - function append(element, insertFirst) { - if(insertFirst && this._node.firstChild) { - this._node.insertBefore(element._node, this._node.firstChild); - } else { - this._node.appendChild(element._node); - } - - return this; - } + return this; + } - /** - * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. - * - * @memberof Chartist.Svg - * @return {Array} A list of classes or an empty array if there are no classes on the current element - */ - function classes() { - return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; - } + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Chartist.Svg + * @return {Array} A list of classes or an empty array if there are no classes on the current element + */ + function classes() { + return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; + } - /** - * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @return {Chartist.Svg} The wrapper of the current element - */ - function addClass(names) { - this._node.setAttribute('class', - this.classes(this._node) - .concat(names.trim().split(/\s+/)) - .filter(function(elem, pos, self) { - return self.indexOf(elem) === pos; - }).join(' ') - ); + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @return {Chartist.Svg} The wrapper of the current element + */ + function addClass(names) { + this._node.setAttribute('class', + this.classes(this._node) + .concat(names.trim().split(/\s+/)) + .filter(function(elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ') + ); + + return this; + } - return this; - } + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Chartist.Svg + * @param {String} names A white space separated list of class names + * @return {Chartist.Svg} The wrapper of the current element + */ + function removeClass(names) { + var removedClasses = names.trim().split(/\s+/); - /** - * Removes one or a space separated list of classes from the current element. - * - * @memberof Chartist.Svg - * @param {String} names A white space separated list of class names - * @return {Chartist.Svg} The wrapper of the current element - */ - function removeClass(names) { - var removedClasses = names.trim().split(/\s+/); + this._node.setAttribute('class', this.classes(this._node).filter(function(name) { + return removedClasses.indexOf(name) === -1; + }).join(' ')); - this._node.setAttribute('class', this.classes(this._node).filter(function(name) { - return removedClasses.indexOf(name) === -1; - }).join(' ')); + return this; + } - return this; - } + /** + * Removes all classes from the current element. + * + * @memberof Chartist.Svg + * @return {Chartist.Svg} The wrapper of the current element + */ + function removeAllClasses() { + this._node.setAttribute('class', ''); - /** - * Removes all classes from the current element. - * - * @memberof Chartist.Svg - * @return {Chartist.Svg} The wrapper of the current element - */ - function removeAllClasses() { - this._node.setAttribute('class', ''); + return this; + } - return this; - } + /** + * Get element height with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Svg + * @return {Number} The elements height in pixels + */ + function height() { + return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; + } - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Svg - * @return {Number} The elements height in pixels - */ - function height() { - return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; - } + /** + * Get element width with fallback to svg BoundingBox or parent container dimensions: + * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + function width() { + return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + } - /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) - * - * @memberof Chartist.Core - * @return {Number} The elements width in pixels - */ - function width() { - return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + /** + * 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. + * **An animations object could look like this:** + * ```javascript + * element.animate({ + * opacity: { + * dur: 1000, + * from: 0, + * to: 1 + * }, + * x1: { + * dur: '1000ms', + * from: 100, + * to: 200, + * easing: 'easeOutQuart' + * }, + * y1: { + * dur: '2s', + * from: 0, + * to: 100 + * } + * }); + * ``` + * **Automatic unit conversion** + * 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. + * **Guided mode** + * 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. + * If guided mode is enabled the following behavior is added: + * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) + * - The animate element will be forced to use `fill="freeze"` + * - 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. + * - After the animation the element attribute value will be set to the `to` value of the animation + * - The animate element is deleted from the DOM + * + * @memberof Chartist.Svg + * @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. + * @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. + * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. + * @return {Chartist.Svg} The current element where the animation was added + */ + function animate(animations, guided, eventEmitter) { + if(guided === undefined) { + guided = true; } - /** - * 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. - * **An animations object could look like this:** - * ```javascript - * element.animate({ - * opacity: { - * dur: 1000, - * from: 0, - * to: 1 - * }, - * x1: { - * dur: '1000ms', - * from: 100, - * to: 200, - * easing: 'easeOutQuart' - * }, - * y1: { - * dur: '2s', - * from: 0, - * to: 100 - * } - * }); - * ``` - * **Automatic unit conversion** - * 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. - * **Guided mode** - * 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. - * If guided mode is enabled the following behavior is added: - * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation - * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) - * - The animate element will be forced to use `fill="freeze"` - * - 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. - * - After the animation the element attribute value will be set to the `to` value of the animation - * - The animate element is deleted from the DOM - * - * @memberof Chartist.Svg - * @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. - * @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. - * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. - * @return {Chartist.Svg} The current element where the animation was added - */ - function animate(animations, guided, eventEmitter) { - if(guided === undefined) { - guided = true; - } - - Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { - - function createAnimate(animationDefinition, guided) { - var attributeProperties = {}, - animate, - timeout, - easing; - - // Check if an easing is specified in the definition object and delete it from the object as it will not - // be part of the animate element attributes. - if(animationDefinition.easing) { - // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object - easing = animationDefinition.easing instanceof Array ? - animationDefinition.easing : - Chartist.Svg.Easing[animationDefinition.easing]; - delete animationDefinition.easing; - } - - // If numeric dur or begin was provided we assume milli seconds - animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); - animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); - - if(easing) { - animationDefinition.calcMode = 'spline'; - animationDefinition.keySplines = easing.join(' '); - animationDefinition.keyTimes = '0;1'; - } - - // Adding "fill: freeze" if we are in guided mode and set initial attribute values - if(guided) { - animationDefinition.fill = 'freeze'; - // Animated property on our element should already be set to the animation from value in guided mode - attributeProperties[attribute] = animationDefinition.from; - this.attr(attributeProperties); - - // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin - // which needs to be in ms aside - timeout = Chartist.stripUnit(animationDefinition.begin || 0); - animationDefinition.begin = 'indefinite'; - } - - animate = this.elem('animate', Chartist.extend({ - attributeName: attribute - }, animationDefinition)); + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + + function createAnimate(animationDefinition, guided) { + var attributeProperties = {}, + animate, + timeout, + easing; + + // Check if an easing is specified in the definition object and delete it from the object as it will not + // be part of the animate element attributes. + if(animationDefinition.easing) { + // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object + easing = animationDefinition.easing instanceof Array ? + animationDefinition.easing : + Chartist.Svg.Easing[animationDefinition.easing]; + delete animationDefinition.easing; + } - if(guided) { - // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout - setTimeout(function() { - // If beginElement fails we set the animated attribute to the end position and remove the animate element - // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in - // the browser. (Currently FF 34 does not support animate elements in foreignObjects) - try { - animate._node.beginElement(); - } catch(err) { - // Set animated attribute to current animated value - attributeProperties[attribute] = animationDefinition.to; - this.attr(attributeProperties); - // Remove the animate element as it's no longer required - animate.remove(); - } - }.bind(this), timeout); - } + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); - if(eventEmitter) { - animate._node.addEventListener('beginEvent', function handleBeginEvent() { - eventEmitter.emit('animationBegin', { - element: this, - animate: animate._node, - params: animationDefinition - }); - }.bind(this)); - } + if(easing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = easing.join(' '); + animationDefinition.keyTimes = '0;1'; + } - animate._node.addEventListener('endEvent', function handleEndEvent() { - if(eventEmitter) { - eventEmitter.emit('animationEnd', { - element: this, - animate: animate._node, - params: animationDefinition - }); - } + // Adding "fill: freeze" if we are in guided mode and set initial attribute values + if(guided) { + animationDefinition.fill = 'freeze'; + // Animated property on our element should already be set to the animation from value in guided mode + attributeProperties[attribute] = animationDefinition.from; + this.attr(attributeProperties); + + // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin + // which needs to be in ms aside + timeout = Chartist.stripUnit(animationDefinition.begin || 0); + animationDefinition.begin = 'indefinite'; + } - if(guided) { + animate = this.elem('animate', Chartist.extend({ + attributeName: attribute + }, animationDefinition)); + + if(guided) { + // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout + setTimeout(function() { + // If beginElement fails we set the animated attribute to the end position and remove the animate element + // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in + // the browser. (Currently FF 34 does not support animate elements in foreignObjects) + try { + animate._node.beginElement(); + } catch(err) { // Set animated attribute to current animated value attributeProperties[attribute] = animationDefinition.to; this.attr(attributeProperties); // Remove the animate element as it's no longer required animate.remove(); } - }.bind(this)); + }.bind(this), timeout); } - // If current attribute is an array of definition objects we create an animate for each and disable guided mode - if(animations[attribute] instanceof Array) { - animations[attribute].forEach(function(animationDefinition) { - createAnimate.bind(this)(animationDefinition, false); + if(eventEmitter) { + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animationDefinition + }); }.bind(this)); - } else { - createAnimate.bind(this)(animations[attribute], guided); } - }.bind(this)); + animate._node.addEventListener('endEvent', function handleEndEvent() { + if(eventEmitter) { + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animationDefinition + }); + } - return this; - } + if(guided) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this)); + } - Chartist.Svg = Chartist.Class.extend({ - constructor: Svg, - attr: attr, - elem: elem, - parent: parent, - root: root, - querySelector: querySelector, - querySelectorAll: querySelectorAll, - foreignObject: foreignObject, - text: text, - empty: empty, - remove: remove, - replace: replace, - append: append, - classes: classes, - addClass: addClass, - removeClass: removeClass, - removeAllClasses: removeAllClasses, - height: height, - width: width, - animate: animate - }); + // If current attribute is an array of definition objects we create an animate for each and disable guided mode + if(animations[attribute] instanceof Array) { + animations[attribute].forEach(function(animationDefinition) { + createAnimate.bind(this)(animationDefinition, false); + }.bind(this)); + } else { + createAnimate.bind(this)(animations[attribute], guided); + } - /** - * 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. - * - * @memberof Chartist.Svg - * @param {String} feature The SVG 1.1 feature that should be checked for support. - * @return {Boolean} True of false if the feature is supported or not - */ - Chartist.Svg.isSupported = function(feature) { - return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); - }; + }.bind(this)); - /** - * 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. - * - * @memberof Chartist.Svg - */ - var easingCubicBeziers = { - easeInSine: [0.47, 0, 0.745, 0.715], - easeOutSine: [0.39, 0.575, 0.565, 1], - easeInOutSine: [0.445, 0.05, 0.55, 0.95], - easeInQuad: [0.55, 0.085, 0.68, 0.53], - easeOutQuad: [0.25, 0.46, 0.45, 0.94], - easeInOutQuad: [0.455, 0.03, 0.515, 0.955], - easeInCubic: [0.55, 0.055, 0.675, 0.19], - easeOutCubic: [0.215, 0.61, 0.355, 1], - easeInOutCubic: [0.645, 0.045, 0.355, 1], - easeInQuart: [0.895, 0.03, 0.685, 0.22], - easeOutQuart: [0.165, 0.84, 0.44, 1], - easeInOutQuart: [0.77, 0, 0.175, 1], - easeInQuint: [0.755, 0.05, 0.855, 0.06], - easeOutQuint: [0.23, 1, 0.32, 1], - easeInOutQuint: [0.86, 0, 0.07, 1], - easeInExpo: [0.95, 0.05, 0.795, 0.035], - easeOutExpo: [0.19, 1, 0.22, 1], - easeInOutExpo: [1, 0, 0, 1], - easeInCirc: [0.6, 0.04, 0.98, 0.335], - easeOutCirc: [0.075, 0.82, 0.165, 1], - easeInOutCirc: [0.785, 0.135, 0.15, 0.86], - easeInBack: [0.6, -0.28, 0.735, 0.045], - easeOutBack: [0.175, 0.885, 0.32, 1.275], - easeInOutBack: [0.68, -0.55, 0.265, 1.55] - }; + return this; + } - Chartist.Svg.Easing = easingCubicBeziers; + Chartist.Svg = Chartist.Class.extend({ + constructor: Svg, + attr: attr, + elem: elem, + parent: parent, + root: root, + querySelector: querySelector, + querySelectorAll: querySelectorAll, + foreignObject: foreignObject, + text: text, + empty: empty, + remove: remove, + replace: replace, + append: append, + classes: classes, + addClass: addClass, + removeClass: removeClass, + removeAllClasses: removeAllClasses, + height: height, + width: width, + animate: animate + }); - /** - * 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. - * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. - * - * @memberof Chartist.Svg - * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) - * @constructor - */ - function SvgList(nodeList) { - var list = this; + /** + * 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. + * + * @memberof Chartist.Svg + * @param {String} feature The SVG 1.1 feature that should be checked for support. + * @return {Boolean} True of false if the feature is supported or not + */ + Chartist.Svg.isSupported = function(feature) { + return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); + }; - this.svgElements = []; - for(var i = 0; i < nodeList.length; i++) { - this.svgElements.push(new Chartist.Svg(nodeList[i])); - } + /** + * 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. + * + * @memberof Chartist.Svg + */ + var easingCubicBeziers = { + easeInSine: [0.47, 0, 0.745, 0.715], + easeOutSine: [0.39, 0.575, 0.565, 1], + easeInOutSine: [0.445, 0.05, 0.55, 0.95], + easeInQuad: [0.55, 0.085, 0.68, 0.53], + easeOutQuad: [0.25, 0.46, 0.45, 0.94], + easeInOutQuad: [0.455, 0.03, 0.515, 0.955], + easeInCubic: [0.55, 0.055, 0.675, 0.19], + easeOutCubic: [0.215, 0.61, 0.355, 1], + easeInOutCubic: [0.645, 0.045, 0.355, 1], + easeInQuart: [0.895, 0.03, 0.685, 0.22], + easeOutQuart: [0.165, 0.84, 0.44, 1], + easeInOutQuart: [0.77, 0, 0.175, 1], + easeInQuint: [0.755, 0.05, 0.855, 0.06], + easeOutQuint: [0.23, 1, 0.32, 1], + easeInOutQuint: [0.86, 0, 0.07, 1], + easeInExpo: [0.95, 0.05, 0.795, 0.035], + easeOutExpo: [0.19, 1, 0.22, 1], + easeInOutExpo: [1, 0, 0, 1], + easeInCirc: [0.6, 0.04, 0.98, 0.335], + easeOutCirc: [0.075, 0.82, 0.165, 1], + easeInOutCirc: [0.785, 0.135, 0.15, 0.86], + easeInBack: [0.6, -0.28, 0.735, 0.045], + easeOutBack: [0.175, 0.885, 0.32, 1.275], + easeInOutBack: [0.68, -0.55, 0.265, 1.55] + }; - // Add delegation methods for Chartist.Svg - Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { - return ['constructor', - 'parent', - 'querySelector', - 'querySelectorAll', - 'replace', - 'append', - 'classes', - 'height', - 'width'].indexOf(prototypeProperty) === -1; - }).forEach(function(prototypeProperty) { - list[prototypeProperty] = function() { - var args = Array.prototype.slice.call(arguments, 0); - list.svgElements.forEach(function(element) { - Chartist.Svg.prototype[prototypeProperty].apply(element, args); - }); - return list; - }; - }); + Chartist.Svg.Easing = easingCubicBeziers; + + /** + * 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. + * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. + * + * @memberof Chartist.Svg + * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) + * @constructor + */ + function SvgList(nodeList) { + var list = this; + + this.svgElements = []; + for(var i = 0; i < nodeList.length; i++) { + this.svgElements.push(new Chartist.Svg(nodeList[i])); } - Chartist.Svg.List = Chartist.Class.extend({ - constructor: SvgList + // Add delegation methods for Chartist.Svg + Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { + return ['constructor', + 'parent', + 'querySelector', + 'querySelectorAll', + 'replace', + 'append', + 'classes', + 'height', + 'width'].indexOf(prototypeProperty) === -1; + }).forEach(function(prototypeProperty) { + list[prototypeProperty] = function() { + var args = Array.prototype.slice.call(arguments, 0); + list.svgElements.forEach(function(element) { + Chartist.Svg.prototype[prototypeProperty].apply(element, args); + }); + return list; + }; }); - }(window, document, Chartist)); - ;/** - * Chartist SVG path module for SVG path description creation and modification. + } + + Chartist.Svg.List = Chartist.Class.extend({ + constructor: SvgList + }); +}(window, document, Chartist)); +;/** + * Chartist SVG path module for SVG path description creation and modification. + * + * @module Chartist.Svg.Path + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; + + /** + * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported. * - * @module Chartist.Svg.Path + * @memberof Chartist.Svg.Path + * @type {Object} */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - /** - * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported. - * - * @memberof Chartist.Svg.Path - * @type {Object} - */ - var elementDescriptions = { - m: ['x', 'y'], - l: ['x', 'y'], - c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'] - }; + var elementDescriptions = { + m: ['x', 'y'], + l: ['x', 'y'], + c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'] + }; - /** - * Default options for newly created SVG path objects. - * - * @memberof Chartist.Svg.Path - * @type {Object} - */ - var defaultOptions = { - // 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. - accuracy: 3 - }; + /** + * Default options for newly created SVG path objects. + * + * @memberof Chartist.Svg.Path + * @type {Object} + */ + var defaultOptions = { + // 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. + accuracy: 3 + }; - function element(command, params, pathElements, pos, relative) { - pathElements.splice(pos, 0, Chartist.extend({ - command: relative ? command.toLowerCase() : command.toUpperCase() - }, params)); - } + function element(command, params, pathElements, pos, relative) { + pathElements.splice(pos, 0, Chartist.extend({ + command: relative ? command.toLowerCase() : command.toUpperCase() + }, params)); + } - function forEachParam(pathElements, cb) { - pathElements.forEach(function(pathElement, pathElementIndex) { - elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) { - cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); - }); + function forEachParam(pathElements, cb) { + pathElements.forEach(function(pathElement, pathElementIndex) { + elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) { + cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); }); - } - - /** - * Used to construct a new path object. - * - * @memberof Chartist.Svg.Path - * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end) - * @param {Object} options Options object that overrides the default objects. See default options for more details. - * @constructor - */ - function SvgPath(close, options) { - this.pathElements = []; - this.pos = 0; - this.close = close; - this.options = Chartist.extend({}, defaultOptions, options); - } + }); + } - /** - * 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. - * - * @memberof Chartist.Svg.Path - * @param {Number} [position] If a number is passed then the cursor is set to this position in the path element array. - * @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. - */ - function position(pos) { - if(pos !== undefined) { - this.pos = Math.max(0, Math.min(this.pathElements.length, pos)); - return this; - } else { - return this.pos; - } - } + /** + * Used to construct a new path object. + * + * @memberof Chartist.Svg.Path + * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end) + * @param {Object} options Options object that overrides the default objects. See default options for more details. + * @constructor + */ + function SvgPath(close, options) { + this.pathElements = []; + this.pos = 0; + this.close = close; + this.options = Chartist.extend({}, defaultOptions, options); + } - /** - * Removes elements from the path starting at the current position. - * - * @memberof Chartist.Svg.Path - * @param {Number} count Number of path elements that should be removed from the current position. - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function remove(count) { - this.pathElements.splice(this.pos, count); + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} [position] If a number is passed then the cursor is set to this position in the path element array. + * @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. + */ + function position(pos) { + if(pos !== undefined) { + this.pos = Math.max(0, Math.min(this.pathElements.length, pos)); return this; + } else { + return this.pos; } + } - /** - * Use this function to add a new move SVG path element. - * - * @memberof Chartist.Svg.Path - * @param {Number} x The x coordinate for the move element. - * @param {Number} y The y coordinate for the move element. - * @param {Boolean} relative If set to true the move element will be created with relative coordinates (lowercase letter) - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function move(x, y, relative) { - element('M', { - x: +x, - y: +y - }, this.pathElements, this.pos++, relative); - return this; - } + /** + * Removes elements from the path starting at the current position. + * + * @memberof Chartist.Svg.Path + * @param {Number} count Number of path elements that should be removed from the current position. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function remove(count) { + this.pathElements.splice(this.pos, count); + return this; + } - /** - * Use this function to add a new line SVG path element. - * - * @memberof Chartist.Svg.Path - * @param {Number} x The x coordinate for the line element. - * @param {Number} y The y coordinate for the line element. - * @param {Boolean} relative If set to true the line element will be created with relative coordinates (lowercase letter) - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function line(x, y, relative) { - element('L', { - x: +x, - y: +y - }, this.pathElements, this.pos++, relative); - return this; - } + /** + * Use this function to add a new move SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The x coordinate for the move element. + * @param {Number} y The y coordinate for the move element. + * @param {Boolean} relative If set to true the move element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function move(x, y, relative) { + element('M', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } - /** - * Use this function to add a new curve SVG path element. - * - * @memberof Chartist.Svg.Path - * @param {Number} x1 The x coordinate for the first control point of the bezier curve. - * @param {Number} y1 The y coordinate for the first control point of the bezier curve. - * @param {Number} x2 The x coordinate for the second control point of the bezier curve. - * @param {Number} y2 The y coordinate for the second control point of the bezier curve. - * @param {Number} x The x coordinate for the target point of the curve element. - * @param {Number} y The y coordinate for the target point of the curve element. - * @param {Boolean} relative If set to true the curve element will be created with relative coordinates (lowercase letter) - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function curve(x1, y1, x2, y2, x, y, relative) { - element('C', { - x1: +x1, - y1: +y1, - x2: +x2, - y2: +y2, - x: +x, - y: +y - }, this.pathElements, this.pos++, relative); - return this; + /** + * Use this function to add a new line SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The x coordinate for the line element. + * @param {Number} y The y coordinate for the line element. + * @param {Boolean} relative If set to true the line element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function line(x, y, relative) { + element('L', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * Use this function to add a new curve SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} x1 The x coordinate for the first control point of the bezier curve. + * @param {Number} y1 The y coordinate for the first control point of the bezier curve. + * @param {Number} x2 The x coordinate for the second control point of the bezier curve. + * @param {Number} y2 The y coordinate for the second control point of the bezier curve. + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} relative If set to true the curve element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function curve(x1, y1, x2, y2, x, y, relative) { + element('C', { + x1: +x1, + y1: +y1, + x2: +x2, + y2: +y2, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function parse(path) { + // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] + var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') + .replace(/([0-9])([A-Za-z])/g, '$1 $2') + .split(/[\s,]+/) + .reduce(function(result, element) { + if(element.match(/[A-Za-z]/)) { + result.push([]); + } + + result[result.length - 1].push(element); + return result; + }, []); + + // If this is a closed path we remove the Z at the end because this is determined by the close option + if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') { + chunks.pop(); } - /** - * 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. - * - * @memberof Chartist.Svg.Path - * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components. - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function parse(path) { - // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] - var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') - .replace(/([0-9])([A-Za-z])/g, '$1 $2') - .split(/[\s,]+/) - .reduce(function(result, element) { - if(element.match(/[A-Za-z]/)) { - result.push([]); - } + // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters + // For example {command: 'M', x: '10', y: '10'} + var elements = chunks.map(function(chunk) { + var command = chunk.shift(), + description = elementDescriptions[command.toLowerCase()]; - result[result.length - 1].push(element); + return Chartist.extend({ + command: command + }, description.reduce(function(result, paramName, index) { + result[paramName] = +chunk[index]; return result; - }, []); + }, {})); + }); - // If this is a closed path we remove the Z at the end because this is determined by the close option - if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') { - chunks.pop(); - } + // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position + var spliceArgs = [this.pos, 0]; + Array.prototype.push.apply(spliceArgs, elements); + Array.prototype.splice.apply(this.pathElements, spliceArgs); + // Increase the internal position by the element count + this.pos += elements.length; - // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters - // For example {command: 'M', x: '10', y: '10'} - var elements = chunks.map(function(chunk) { - var command = chunk.shift(), - description = elementDescriptions[command.toLowerCase()]; - - return Chartist.extend({ - command: command - }, description.reduce(function(result, paramName, index) { - result[paramName] = +chunk[index]; - return result; - }, {})); - }); + return this; + } - // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position - var spliceArgs = [this.pos, 0]; - Array.prototype.push.apply(spliceArgs, elements); - Array.prototype.splice.apply(this.pathElements, spliceArgs); - // Increase the internal position by the element count - this.pos += elements.length; + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @return {String} + */ + function stringify() { + var accuracyMultiplier = Math.pow(10, this.options.accuracy); + + return this.pathElements.reduce(function(path, pathElement) { + var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) { + return this.options.accuracy ? + (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) : + pathElement[paramName]; + }.bind(this)); - return this; - } + return path + pathElement.command + params.join(','); + }.bind(this), '') + (this.close ? 'Z' : ''); + } - /** - * 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. - * - * @memberof Chartist.Svg.Path - * @return {String} - */ - function stringify() { - var accuracyMultiplier = Math.pow(10, this.options.accuracy); - - return this.pathElements.reduce(function(path, pathElement) { - var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) { - return this.options.accuracy ? - (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) : - pathElement[paramName]; - }.bind(this)); + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function scale(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] *= paramName[0] === 'x' ? x : y; + }); + return this; + } - return path + pathElement.command + params.join(','); - }.bind(this), '') + (this.close ? 'Z' : ''); - } + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function translate(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] += paramName[0] === 'x' ? x : y; + }); + return this; + } - /** - * 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. - * - * @memberof Chartist.Svg.Path - * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements. - * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements. - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function scale(x, y) { - forEachParam(this.pathElements, function(pathElement, paramName) { - pathElement[paramName] *= paramName[0] === 'x' ? x : y; - }); - return this; - } + /** + * 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. + * The method signature of the callback function looks like this: + * ```javascript + * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) + * ``` + * 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. + * + * @memberof Chartist.Svg.Path + * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description. + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function transform(transformFnc) { + forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) { + var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + if(transformed || transformed === 0) { + pathElement[paramName] = transformed; + } + }); + return this; + } - /** - * 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. - * - * @memberof Chartist.Svg.Path - * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements. - * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements. - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function translate(x, y) { - forEachParam(this.pathElements, function(pathElement, paramName) { - pathElement[paramName] += paramName[0] === 'x' ? x : y; - }); - return this; - } + /** + * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. + * + * @memberof Chartist.Svg.Path + * @return {Chartist.Svg.Path} + */ + function clone() { + var c = new Chartist.Svg.Path(this.close); + c.pos = this.pos; + c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { + return Chartist.extend({}, pathElement); + }); + c.options = Chartist.extend({}, this.options); + return c; + } - /** - * 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. - * The method signature of the callback function looks like this: - * ```javascript - * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) - * ``` - * 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. - * - * @memberof Chartist.Svg.Path - * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description. - * @return {Chartist.Svg.Path} The current path object for easy call chaining. - */ - function transform(transformFnc) { - forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) { - var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); - if(transformed || transformed === 0) { - pathElement[paramName] = transformed; - } - }); - return this; + Chartist.Svg.Path = Chartist.Class.extend({ + constructor: SvgPath, + position: position, + remove: remove, + move: move, + line: line, + curve: curve, + scale: scale, + translate: translate, + transform: transform, + parse: parse, + stringify: stringify, + clone: clone + }); + + Chartist.Svg.Path.elementDescriptions = elementDescriptions; +}(window, document, Chartist)); +;/** + * Axis base class used to implement different axis types + * + * @module Chartist.Axis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + var axisUnits = { + x: { + pos: 'x', + len: 'width', + dir: 'horizontal', + rectStart: 'x1', + rectEnd: 'x2', + rectOffset: 'y2' + }, + y: { + pos: 'y', + len: 'height', + dir: 'vertical', + rectStart: 'y2', + rectEnd: 'y1', + rectOffset: 'x1' } + }; - /** - * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. - * - * @memberof Chartist.Svg.Path - * @return {Chartist.Svg.Path} - */ - function clone() { - var c = new Chartist.Svg.Path(this.close); - c.pos = this.pos; - c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { - return Chartist.extend({}, pathElement); - }); - c.options = Chartist.extend({}, this.options); - return c; + function Axis(units, chartRect, transform, labelOffset, options) { + this.units = units; + this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; + this.chartRect = chartRect; + this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; + this.gridOffset = chartRect[units.rectOffset]; + this.transform = transform; + this.labelOffset = labelOffset; + this.options = options; + } + + Chartist.Axis = Chartist.Class.extend({ + constructor: Axis, + projectValue: function(value, index, data) { + throw new Error('Base axis can\'t be instantiated!'); } + }); + + Chartist.Axis.units = axisUnits; + +}(window, document, Chartist)); +;/** + * The linear scale axis uses standard linear scale projection of values along an axis. + * + * @module Chartist.LinearScaleAxis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) { + Chartist.LinearScaleAxis.super.constructor.call(this, + axisUnit, + chartRect, + transform, + labelOffset, + options); + + this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); + } - Chartist.Svg.Path = Chartist.Class.extend({ - constructor: SvgPath, - position: position, - remove: remove, - move: move, - line: line, - curve: curve, - scale: scale, - translate: translate, - transform: transform, - parse: parse, - stringify: stringify, - clone: clone - }); + function projectValue(value) { + return { + pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step), + len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) + }; + } - Chartist.Svg.Path.elementDescriptions = elementDescriptions; - }(window, document, Chartist)); - ;/** - * Axis base class used to implement different axis types - * - * @module Chartist.Axis - */ - /* global Chartist */ - (function (window, document, Chartist) { - 'use strict'; - - var axisUnits = { - x: { - pos: 'x', - len: 'width', - dir: 'horizontal', - rectStart: 'x1', - rectEnd: 'x2', - rectOffset: 'y2' - }, - y: { - pos: 'y', - len: 'height', - dir: 'vertical', - rectStart: 'y2', - rectEnd: 'y1', - rectOffset: 'x1' - } + Chartist.LinearScaleAxis = Chartist.Axis.extend({ + constructor: LinearScaleAxis, + projectValue: projectValue + }); + +}(window, document, Chartist)); +;/** + * Step axis for step based charts like bar chart or step based line chart + * + * @module Chartist.StepAxis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + function StepAxis(axisUnit, chartRect, transform, labelOffset, options) { + Chartist.StepAxis.super.constructor.call(this, + axisUnit, + chartRect, + transform, + labelOffset, + options); + + this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); + } + + function projectValue(value, index) { + return { + pos: this.stepLength * index, + len: this.stepLength }; + } + + Chartist.StepAxis = Chartist.Axis.extend({ + constructor: StepAxis, + projectValue: projectValue + }); + +}(window, document, Chartist)); +;/** + * 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. + * + * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. + * + * @module Chartist.Line + */ +/* global Chartist */ +(function(window, document, Chartist){ + 'use strict'; - function Axis(units, chartRect, transform, labelOffset, options) { - this.units = units; - this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; - this.chartRect = chartRect; - this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; - this.gridOffset = chartRect[units.rectOffset]; - this.transform = transform; - this.labelOffset = labelOffset; - this.options = options; + /** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Line + */ + var defaultOptions = { + // Options for X-Axis + axisX: { + // The offset of the labels to the chart area + offset: 30, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: Chartist.noop + }, + // Options for Y-Axis + axisY: { + // The offset of the labels to the chart area + offset: 40, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20 + }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // If the line should be drawn or not + showLine: true, + // If dots should be drawn or not + showPoint: true, + // If the line chart should draw an area + showArea: false, + // The base for the area chart that will be used to close the area shape (is normally 0) + areaBase: 0, + // 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. + lineSmooth: true, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + low: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + high: undefined, + // 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} + chartPadding: 5, + // 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. + fullWidth: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // Override the class names that get used to generate the SVG structure of the chart + 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', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' } + }; - Chartist.Axis = Chartist.Class.extend({ - constructor: Axis, - projectValue: function(value, index, data) { - throw new Error('Base axis can\'t be instantiated!'); + /** + * Creates a new chart + * + */ + function createChart(options) { + var seriesGroups = [], + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), + normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding); + + // Create new svg object + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); + + var highLow = Chartist.getHighLow(normalizedData); + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); + + var axisX = new Chartist.StepAxis( + Chartist.Axis.units.x, + chartRect, + function xAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { + stepCount: this.data.labels.length, + stretch: options.fullWidth } - }); + ); + + var axisY = new Chartist.LinearScaleAxis( + Chartist.Axis.units.y, + chartRect, + function yAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) + }, + { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace + } + ); + + // Start drawing + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), + gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + + Chartist.createAxis( + axisX, + this.data.labels, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + Chartist.createAxis( + axisY, + axisY.bounds.values, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + // Draw the series + this.data.series.forEach(function(series, seriesIndex) { + seriesGroups[seriesIndex] = this.svg.elem('g'); + + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesGroups[seriesIndex].attr({ + 'series-name': series.name, + 'meta': Chartist.serialize(series.meta) + }, Chartist.xmlNs.uri); + + // Use series class from series data or if not set generate one + seriesGroups[seriesIndex].addClass([ + options.classNames.series, + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) + ].join(' ')); + + var pathCoordinates = []; + + normalizedData[seriesIndex].forEach(function(value, valueIndex) { + var p = { + x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + }; + pathCoordinates.push(p.x, p.y); + + //If we should show points we need to create them now to avoid secondary loop + // Small offset for Firefox to render squares correctly + if (options.showPoint) { + var point = seriesGroups[seriesIndex].elem('line', { + x1: p.x, + y1: p.y, + x2: p.x + 0.01, + y2: p.y + }, options.classNames.point).attr({ + 'value': value, + 'meta': Chartist.getMetaData(series, valueIndex) + }, Chartist.xmlNs.uri); - Chartist.Axis.units = axisUnits; + this.eventEmitter.emit('draw', { + type: 'point', + value: value, + index: valueIndex, + group: seriesGroups[seriesIndex], + element: point, + x: p.x, + y: p.y + }); + } + }.bind(this)); - }(window, document, Chartist)); - ;/** - * The linear scale axis uses standard linear scale projection of values along an axis. - * - * @module Chartist.LinearScaleAxis - */ - /* global Chartist */ - (function (window, document, Chartist) { - 'use strict'; + // TODO: Nicer handling of conditions, maybe composition? + if (options.showLine || options.showArea) { + var smoothing = typeof options.lineSmooth === 'function' ? + options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()), + path = smoothing(pathCoordinates); + + if(options.showLine) { + var line = seriesGroups[seriesIndex].elem('path', { + d: path.stringify() + }, options.classNames.line, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); - function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) { - Chartist.LinearScaleAxis.super.constructor.call(this, - axisUnit, - chartRect, - transform, - labelOffset, - options); + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[seriesIndex], + path: path.clone(), + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], + element: line + }); + } - this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); - } + if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; + + // Clone original path and splice our new area path to add the missing path elements to close the area shape + var areaPath = path.clone(); + // Modify line path and add missing elements for area + areaPath.position(0) + .remove(1) + .move(chartRect.x1, areaBaseProjected) + .line(pathCoordinates[0], pathCoordinates[1]) + .position(areaPath.pathElements.length) + .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); + + // Create the new path for the area shape with the area class from the options + var area = seriesGroups[seriesIndex].elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); - function projectValue(value) { - return { - pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step), - len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) - }; - } + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[seriesIndex], + path: areaPath.clone(), + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], + element: area + }); + } + } + }.bind(this)); - Chartist.LinearScaleAxis = Chartist.Axis.extend({ - constructor: LinearScaleAxis, - projectValue: projectValue + this.eventEmitter.emit('created', { + bounds: axisY.bounds, + chartRect: chartRect, + svg: this.svg, + options: options }); + } - }(window, document, Chartist)); - ;/** - * Step axis for step based charts like bar chart or step based line chart + /** + * This method creates a new line chart. + * + * @memberof Chartist.Line + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // Create a simple line chart + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // As options we currently only set a static size of 300x200 px + * var options = { + * width: '300px', + * height: '200px' + * }; + * + * // 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 + * new Chartist.Line('.ct-chart', data, options); + * + * @example + * // Use specific interpolation function with configuration from the Chartist.Interpolation module + * + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [ + * [1, 1, 8, 1, 7] + * ] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 0.2 + * }) + * }); + * + * @example + * // Create a line chart with responsive options + * + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. + * var responsiveOptions = [ + * ['screen and (min-width: 641px) and (max-width: 1024px)', { + * showPoint: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return Mon, Tue, Wed etc. on medium screens + * return value.slice(0, 3); + * } + * } + * }], + * ['screen and (max-width: 640px)', { + * showLine: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return M, T, W etc. on small screens + * return value[0]; + * } + * } + * }] + * ]; + * + * new Chartist.Line('.ct-chart', data, null, responsiveOptions); * - * @module Chartist.StepAxis */ - /* global Chartist */ - (function (window, document, Chartist) { - 'use strict'; - - function StepAxis(axisUnit, chartRect, transform, labelOffset, options) { - Chartist.StepAxis.super.constructor.call(this, - axisUnit, - chartRect, - transform, - labelOffset, - options); - - this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); - } - - function projectValue(value, index) { - return { - pos: this.stepLength * index, - len: this.stepLength - }; - } + function Line(query, data, options, responsiveOptions) { + Chartist.Line.super.constructor.call(this, + query, + data, + defaultOptions, + Chartist.extend({}, defaultOptions, options), + responsiveOptions); + } - Chartist.StepAxis = Chartist.Axis.extend({ - constructor: StepAxis, - projectValue: projectValue - }); + // Creating line chart type in Chartist namespace + Chartist.Line = Chartist.Base.extend({ + constructor: Line, + createChart: createChart + }); + +}(window, document, Chartist)); +;/** + * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. + * + * @module Chartist.Bar + */ +/* global Chartist */ +(function(window, document, Chartist){ + 'use strict'; - }(window, document, Chartist)); - ;/** - * 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. - * - * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. + /** + * Default options in bar charts. Expand the code view to see a detailed list of options with comments. * - * @module Chartist.Line + * @memberof Chartist.Bar */ - /* global Chartist */ - (function(window, document, Chartist){ - 'use strict'; - - /** - * Default options in line charts. Expand the code view to see a detailed list of options with comments. - * - * @memberof Chartist.Line - */ - var defaultOptions = { - // Options for X-Axis - axisX: { - // The offset of the labels to the chart area - offset: 30, - // Allows you to correct label positioning on this axis by positive or negative x and y offset. - labelOffset: { - x: 0, - y: 0 - }, - // If labels should be shown or not - showLabel: true, - // If the axis grid should be drawn or not - showGrid: true, - // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop + var defaultOptions = { + // Options for X-Axis + axisX: { + // The offset of the chart drawing area to the border of the container + offset: 30, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 }, - // Options for Y-Axis - axisY: { - // The offset of the labels to the chart area - offset: 40, - // Allows you to correct label positioning on this axis by positive or negative x and y offset. - labelOffset: { - x: 0, - y: 0 - }, - // If labels should be shown or not - showLabel: true, - // If the axis grid should be drawn or not - showGrid: true, - // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop, - // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20 + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum width in pixel of the scale steps + scaleMinSpace: 40 + }, + // Options for Y-Axis + axisY: { + // The offset of the chart drawing area to the border of the container + offset: 40, + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 }, - // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - width: undefined, - // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - height: undefined, - // If the line should be drawn or not - showLine: true, - // If dots should be drawn or not - showPoint: true, - // If the line chart should draw an area - showArea: false, - // The base for the area chart that will be used to close the area shape (is normally 0) - areaBase: 0, - // 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. - lineSmooth: true, - // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - low: undefined, - // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - high: undefined, - // Padding of the chart drawing area to the container element and labels - chartPadding: 5, - // 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. - fullWidth: false, - // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. - reverseData: false, - // Override the class names that get used to generate the SVG structure of the chart - 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', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }; + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20 + }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + high: undefined, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + low: undefined, + // 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} + chartPadding: 5, + // Specify the distance in pixel of bars in a group + seriesBarDistance: 15, + // If set to true this property will cause the series bars to be stacked and 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. + stackBars: false, + // 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. + horizontalBars: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // Override the class names that get used to generate the SVG structure of the chart + classNames: { + chart: 'ct-chart-bar', + label: 'ct-label', + labelGroup: 'ct-labels', + series: 'ct-series', + bar: 'ct-bar', + grid: 'ct-grid', + gridGroup: 'ct-grids', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal' + } + }; - /** - * Creates a new chart - * - */ - function createChart(options) { - var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); + /** + * Creates a new chart + * + */ + function createChart(options) { + var seriesGroups = [], + normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), + normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding), + highLow; + + // Create new svg element + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + + if(options.stackBars) { + // If stacked bars we need to calculate the high low from stacked values from each series + var serialSums = Chartist.serialMap(normalizedData, function serialSums() { + return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); + }); + + highLow = Chartist.getHighLow([serialSums]); + } else { + highLow = Chartist.getHighLow(normalizedData); + } + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); - // Create new svg object - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); - var chartRect = Chartist.createChartRect(this.svg, options); + var valueAxis, + labelAxis; - var highLow = Chartist.getHighLow(normalizedData); - // Overrides of high / low from settings - highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); - highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); + if(options.horizontalBars) { + labelAxis = new Chartist.StepAxis( + Chartist.Axis.units.y, + chartRect, + function timeAxisTransform(projectedValue) { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + return projectedValue; + }, + { + x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length + }, + { + stepCount: this.data.labels.length, + stretch: options.fullHeight + } + ); - var axisX = new Chartist.StepAxis( + valueAxis = new Chartist.LinearScaleAxis( Chartist.Axis.units.x, chartRect, - function xAxisTransform(projectedValue) { + function valueAxisTransform(projectedValue) { projectedValue.pos = chartRect.x1 + projectedValue.pos; return projectedValue; }, @@ -2461,910 +2881,504 @@ y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) }, { - stepCount: this.data.labels.length, - stretch: options.fullWidth + highLow: highLow, + scaleMinSpace: options.axisX.scaleMinSpace, + referenceValue: 0 + } + ); + } else { + labelAxis = new Chartist.StepAxis( + Chartist.Axis.units.x, + chartRect, + function timeAxisTransform(projectedValue) { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + return projectedValue; + }, + { + x: options.axisX.labelOffset.x, + y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) + }, + { + stepCount: this.data.labels.length } ); - var axisY = new Chartist.LinearScaleAxis( + valueAxis = new Chartist.LinearScaleAxis( Chartist.Axis.units.y, chartRect, - function yAxisTransform(projectedValue) { + function valueAxisTransform(projectedValue) { projectedValue.pos = chartRect.y1 - projectedValue.pos; return projectedValue; }, { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), + x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) }, { highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace + scaleMinSpace: options.axisY.scaleMinSpace, + referenceValue: 0 } ); + } - // Start drawing - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), - gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); - - Chartist.createAxis( - axisX, - this.data.labels, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); - - Chartist.createAxis( - axisY, - axisY.bounds.values, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); - - // Draw the series - this.data.series.forEach(function(series, seriesIndex) { - seriesGroups[seriesIndex] = this.svg.elem('g'); - - // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[seriesIndex].attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) + // Start drawing + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), + gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup), + // Projected 0 point + zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos), + // Used to track the screen coordinates of stacked bars + stackedBarValues = []; + + Chartist.createAxis( + labelAxis, + this.data.labels, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + Chartist.createAxis( + valueAxis, + valueAxis.bounds.values, + chartRect, + gridGroup, + labelGroup, + this.supportsForeignObject, + options, + this.eventEmitter + ); + + // Draw the series + this.data.series.forEach(function(series, seriesIndex) { + // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. + var biPol = seriesIndex - (this.data.series.length - 1) / 2, + // Half of the period width between vertical grid lines used to position bars + periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2; + + seriesGroups[seriesIndex] = this.svg.elem('g'); + + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesGroups[seriesIndex].attr({ + 'series-name': series.name, + 'meta': Chartist.serialize(series.meta) + }, Chartist.xmlNs.uri); + + // Use series class from series data or if not set generate one + seriesGroups[seriesIndex].addClass([ + options.classNames.series, + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) + ].join(' ')); + + normalizedData[seriesIndex].forEach(function(value, valueIndex) { + var projected = { + x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + }, + bar, + previousStack; + + // Offset to center bar between grid lines + projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); + // Using bi-polar offset for multiple series if no stacked bars are used + projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + + // Enter value in stacked bar values used to remember previous screen value for stacking up bars + previousStack = stackedBarValues[valueIndex] || zeroPoint; + stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); + + var positions = {}; + positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; + positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; + // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line + positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; + + bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({ + 'value': value, + 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); - // Use series class from series data or if not set generate one - seriesGroups[seriesIndex].addClass([ - options.classNames.series, - (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) - ].join(' ')); - - var pathCoordinates = []; - - normalizedData[seriesIndex].forEach(function(value, valueIndex) { - var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos - }; - pathCoordinates.push(p.x, p.y); - - //If we should show points we need to create them now to avoid secondary loop - // Small offset for Firefox to render squares correctly - if (options.showPoint) { - var point = seriesGroups[seriesIndex].elem('line', { - x1: p.x, - y1: p.y, - x2: p.x + 0.01, - y2: p.y - }, options.classNames.point).attr({ - 'value': value, - 'meta': Chartist.getMetaData(series, valueIndex) - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'point', - value: value, - index: valueIndex, - group: seriesGroups[seriesIndex], - element: point, - x: p.x, - y: p.y - }); - } - }.bind(this)); - - // TODO: Nicer handling of conditions, maybe composition? - if (options.showLine || options.showArea) { - var smoothing = typeof options.lineSmooth === 'function' ? - options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()), - path = smoothing(pathCoordinates); - - if(options.showLine) { - var line = seriesGroups[seriesIndex].elem('path', { - d: path.stringify() - }, options.classNames.line, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[seriesIndex], - path: path.clone(), - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: line - }); - } - - if(options.showArea) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); - - // We project the areaBase value into screen coordinates - var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; - - // Clone original path and splice our new area path to add the missing path elements to close the area shape - var areaPath = path.clone(); - // Modify line path and add missing elements for area - areaPath.position(0) - .remove(1) - .move(chartRect.x1, areaBaseProjected) - .line(pathCoordinates[0], pathCoordinates[1]) - .position(areaPath.pathElements.length) - .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); - - // Create the new path for the area shape with the area class from the options - var area = seriesGroups[seriesIndex].elem('path', { - d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); - - this.eventEmitter.emit('draw', { - type: 'area', - values: normalizedData[seriesIndex], - path: areaPath.clone(), - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: area - }); - } - } + this.eventEmitter.emit('draw', Chartist.extend({ + type: 'bar', + value: value, + index: valueIndex, + chartRect: chartRect, + group: seriesGroups[seriesIndex], + element: bar + }, positions)); }.bind(this)); + }.bind(this)); - this.eventEmitter.emit('created', { - bounds: axisY.bounds, - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new line chart. - * - * @memberof Chartist.Line - * @param {String|Node} query A selector query string or directly a DOM element - * @param {Object} data The data object that needs to consist of a labels and a series array - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object which exposes the API for the created chart - * - * @example - * // Create a simple line chart - * var data = { - * // A labels array that can contain any sort of values - * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], - * // Our series array that contains series objects or in this case series data arrays - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // As options we currently only set a static size of 300x200 px - * var options = { - * width: '300px', - * height: '200px' - * }; - * - * // 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 - * new Chartist.Line('.ct-chart', data, options); - * - * @example - * // Use specific interpolation function with configuration from the Chartist.Interpolation module - * - * var chart = new Chartist.Line('.ct-chart', { - * labels: [1, 2, 3, 4, 5], - * series: [ - * [1, 1, 8, 1, 7] - * ] - * }, { - * lineSmooth: Chartist.Interpolation.cardinal({ - * tension: 0.2 - * }) - * }); - * - * @example - * // Create a line chart with responsive options - * - * var data = { - * // A labels array that can contain any sort of values - * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], - * // Our series array that contains series objects or in this case series data arrays - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. - * var responsiveOptions = [ - * ['screen and (min-width: 641px) and (max-width: 1024px)', { - * showPoint: false, - * axisX: { - * labelInterpolationFnc: function(value) { - * // Will return Mon, Tue, Wed etc. on medium screens - * return value.slice(0, 3); - * } - * } - * }], - * ['screen and (max-width: 640px)', { - * showLine: false, - * axisX: { - * labelInterpolationFnc: function(value) { - * // Will return M, T, W etc. on small screens - * return value[0]; - * } - * } - * }] - * ]; - * - * new Chartist.Line('.ct-chart', data, null, responsiveOptions); - * - */ - function Line(query, data, options, responsiveOptions) { - Chartist.Line.super.constructor.call(this, - query, - data, - Chartist.extend({}, defaultOptions, options), - responsiveOptions); - } - - // Creating line chart type in Chartist namespace - Chartist.Line = Chartist.Base.extend({ - constructor: Line, - createChart: createChart + this.eventEmitter.emit('created', { + bounds: valueAxis.bounds, + chartRect: chartRect, + svg: this.svg, + options: options }); + } - }(window, document, Chartist)); - ;/** - * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. + /** + * This method creates a new bar chart and returns API object that you can use for later changes. + * + * @memberof Chartist.Bar + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // Create a simple bar chart + * var data = { + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // 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. + * new Chartist.Bar('.ct-chart', data); + * + * @example + * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 + * new Chartist.Bar('.ct-chart', { + * labels: [1, 2, 3, 4, 5, 6, 7], + * series: [ + * [1, 3, 2, -5, -3, 1, -6], + * [-5, -2, -4, -1, 2, -3, 1] + * ] + * }, { + * seriesBarDistance: 12, + * low: -10, + * high: 10 + * }); * - * @module Chartist.Bar */ - /* global Chartist */ - (function(window, document, Chartist){ - 'use strict'; - - /** - * Default options in bar charts. Expand the code view to see a detailed list of options with comments. - * - * @memberof Chartist.Bar - */ - var defaultOptions = { - // Options for X-Axis - axisX: { - // The offset of the chart drawing area to the border of the container - offset: 30, - // Allows you to correct label positioning on this axis by positive or negative x and y offset. - labelOffset: { - x: 0, - y: 0 - }, - // If labels should be shown or not - showLabel: true, - // If the axis grid should be drawn or not - showGrid: true, - // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop, - // This value specifies the minimum width in pixel of the scale steps - scaleMinSpace: 40 - }, - // Options for Y-Axis - axisY: { - // The offset of the chart drawing area to the border of the container - offset: 40, - // Allows you to correct label positioning on this axis by positive or negative x and y offset. - labelOffset: { - x: 0, - y: 0 - }, - // If labels should be shown or not - showLabel: true, - // If the axis grid should be drawn or not - showGrid: true, - // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop, - // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20 - }, - // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - width: undefined, - // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - height: undefined, - // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value - high: undefined, - // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value - low: undefined, - // Padding of the chart drawing area to the container element and labels - chartPadding: 5, - // Specify the distance in pixel of bars in a group - seriesBarDistance: 15, - // If set to true this property will cause the series bars to be stacked and 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. - stackBars: false, - // 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. - horizontalBars: false, - // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. - reverseData: false, - // Override the class names that get used to generate the SVG structure of the chart - classNames: { - chart: 'ct-chart-bar', - label: 'ct-label', - labelGroup: 'ct-labels', - series: 'ct-series', - bar: 'ct-bar', - grid: 'ct-grid', - gridGroup: 'ct-grids', - vertical: 'ct-vertical', - horizontal: 'ct-horizontal' - } - }; - - /** - * Creates a new chart - * - */ - function createChart(options) { - var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), - highLow; - - // Create new svg element - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - - if(options.stackBars) { - // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = Chartist.serialMap(normalizedData, function serialSums() { - return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); - }); - - highLow = Chartist.getHighLow([serialSums]); - } else { - highLow = Chartist.getHighLow(normalizedData); - } - // Overrides of high / low from settings - highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); - highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); - - var chartRect = Chartist.createChartRect(this.svg, options); - - var valueAxis, - labelAxis; - - if(options.horizontalBars) { - labelAxis = new Chartist.StepAxis( - Chartist.Axis.units.y, - chartRect, - function timeAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length - }, - { - stepCount: this.data.labels.length, - stretch: options.fullHeight - } - ); - - valueAxis = new Chartist.LinearScaleAxis( - Chartist.Axis.units.x, - chartRect, - function valueAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, - { - highLow: highLow, - scaleMinSpace: options.axisX.scaleMinSpace, - referenceValue: 0 - } - ); - } else { - labelAxis = new Chartist.StepAxis( - Chartist.Axis.units.x, - chartRect, - function timeAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, - { - stepCount: this.data.labels.length - } - ); - - valueAxis = new Chartist.LinearScaleAxis( - Chartist.Axis.units.y, - chartRect, - function valueAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) - }, - { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - referenceValue: 0 - } - ); - } - - // Start drawing - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), - gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup), - // Projected 0 point - zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos), - // Used to track the screen coordinates of stacked bars - stackedBarValues = []; - - Chartist.createAxis( - labelAxis, - this.data.labels, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); - - Chartist.createAxis( - valueAxis, - valueAxis.bounds.values, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); - - // Draw the series - this.data.series.forEach(function(series, seriesIndex) { - // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = seriesIndex - (this.data.series.length - 1) / 2, - // Half of the period width between vertical grid lines used to position bars - periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2; - - seriesGroups[seriesIndex] = this.svg.elem('g'); - - // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[seriesIndex].attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); - - // Use series class from series data or if not set generate one - seriesGroups[seriesIndex].addClass([ - options.classNames.series, - (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) - ].join(' ')); - - normalizedData[seriesIndex].forEach(function(value, valueIndex) { - var projected = { - x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos - }, - bar, - previousStack; - - // Offset to center bar between grid lines - projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); - // Using bi-polar offset for multiple series if no stacked bars are used - projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); - - // Enter value in stacked bar values used to remember previous screen value for stacking up bars - previousStack = stackedBarValues[valueIndex] || zeroPoint; - stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); - - var positions = {}; - positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; - positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; - // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; - positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; - - bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({ - 'value': value, - 'meta': Chartist.getMetaData(series, valueIndex) - }, Chartist.xmlNs.uri); + function Bar(query, data, options, responsiveOptions) { + Chartist.Bar.super.constructor.call(this, + query, + data, + defaultOptions, + Chartist.extend({}, defaultOptions, options), + responsiveOptions); + } - this.eventEmitter.emit('draw', Chartist.extend({ - type: 'bar', - value: value, - index: valueIndex, - chartRect: chartRect, - group: seriesGroups[seriesIndex], - element: bar - }, positions)); - }.bind(this)); - }.bind(this)); + // Creating bar chart type in Chartist namespace + Chartist.Bar = Chartist.Base.extend({ + constructor: Bar, + createChart: createChart + }); + +}(window, document, Chartist)); +;/** + * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts + * + * @module Chartist.Pie + */ +/* global Chartist */ +(function(window, document, Chartist) { + 'use strict'; - this.eventEmitter.emit('created', { - bounds: valueAxis.bounds, - chartRect: chartRect, - svg: this.svg, - options: options - }); - } + /** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Pie + */ + var defaultOptions = { + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // 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} + chartPadding: 5, + // Override the class names that get used to generate the SVG structure of the chart + classNames: { + chart: 'ct-chart-pie', + series: 'ct-series', + slice: 'ct-slice', + donut: 'ct-donut', + label: 'ct-label' + }, + // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. + startAngle: 0, + // 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. + total: undefined, + // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. + donut: false, + // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. + donutWidth: 60, + // If a label should be shown or not + showLabel: true, + // 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. + labelOffset: 0, + // An interpolation function for the label value + labelInterpolationFnc: Chartist.noop, + // 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. + labelDirection: 'neutral', + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false + }; - /** - * This method creates a new bar chart and returns API object that you can use for later changes. - * - * @memberof Chartist.Bar - * @param {String|Node} query A selector query string or directly a DOM element - * @param {Object} data The data object that needs to consist of a labels and a series array - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object which exposes the API for the created chart - * - * @example - * // Create a simple bar chart - * var data = { - * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], - * series: [ - * [5, 2, 4, 2, 0] - * ] - * }; - * - * // 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. - * new Chartist.Bar('.ct-chart', data); - * - * @example - * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 - * new Chartist.Bar('.ct-chart', { - * labels: [1, 2, 3, 4, 5, 6, 7], - * series: [ - * [1, 3, 2, -5, -3, 1, -6], - * [-5, -2, -4, -1, 2, -3, 1] - * ] - * }, { - * seriesBarDistance: 12, - * low: -10, - * high: 10 - * }); - * - */ - function Bar(query, data, options, responsiveOptions) { - Chartist.Bar.super.constructor.call(this, - query, - data, - Chartist.extend({}, defaultOptions, options), - responsiveOptions); + /** + * Determines SVG anchor position based on direction and center parameter + * + * @param center + * @param label + * @param direction + * @return {string} + */ + function determineAnchorPosition(center, label, direction) { + var toTheRight = label.x > center.x; + + if(toTheRight && direction === 'explode' || + !toTheRight && direction === 'implode') { + return 'start'; + } else if(toTheRight && direction === 'implode' || + !toTheRight && direction === 'explode') { + return 'end'; + } else { + return 'middle'; } + } - // Creating bar chart type in Chartist namespace - Chartist.Bar = Chartist.Base.extend({ - constructor: Bar, - createChart: createChart - }); - - }(window, document, Chartist)); - ;/** - * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts + /** + * Creates the pie chart * - * @module Chartist.Pie + * @param options */ - /* global Chartist */ - (function(window, document, Chartist) { - 'use strict'; - - /** - * Default options in line charts. Expand the code view to see a detailed list of options with comments. - * - * @memberof Chartist.Pie - */ - var defaultOptions = { - // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') - width: undefined, - // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') - height: undefined, - // Padding of the chart drawing area to the container element and labels - chartPadding: 5, - // Override the class names that get used to generate the SVG structure of the chart - classNames: { - chart: 'ct-chart-pie', - series: 'ct-series', - slice: 'ct-slice', - donut: 'ct-donut', - label: 'ct-label' - }, - // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. - startAngle: 0, - // 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. - total: undefined, - // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. - donut: false, - // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. - donutWidth: 60, - // If a label should be shown or not - showLabel: true, - // 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. - labelOffset: 0, - // An interpolation function for the label value - labelInterpolationFnc: Chartist.noop, - // 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. - labelDirection: 'neutral', - // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. - reverseData: false + function createChart(options) { + var seriesGroups = [], + chartRect, + radius, + labelRadius, + totalDataSum, + startAngle = options.startAngle, + dataArray = Chartist.getDataArray(this.data, options.reverseData); + + // Create SVG.js draw + this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + // Calculate charting rect + chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); + // Get biggest circle radius possible within chartRect + radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + // Calculate total of all series to get reference value or use total reference from optional options + totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { + return previousValue + currentValue; + }, 0); + + // 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 ? options.donutWidth / 2 : 0; + + // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius + // see https://github.com/gionkunz/chartist-js/issues/21 + labelRadius = options.donut ? radius : radius / 2; + // Add the offset to the labelRadius where a negative offset means closed to the center of the chart + labelRadius += options.labelOffset; + + // Calculate end angle based on total sum and current data value and offset with padding + var center = { + x: chartRect.x1 + chartRect.width() / 2, + y: chartRect.y2 + chartRect.height() / 2 }; - /** - * Determines SVG anchor position based on direction and center parameter - * - * @param center - * @param label - * @param direction - * @return {string} - */ - function determineAnchorPosition(center, label, direction) { - var toTheRight = label.x > center.x; - - if(toTheRight && direction === 'explode' || - !toTheRight && direction === 'implode') { - return 'start'; - } else if(toTheRight && direction === 'implode' || - !toTheRight && direction === 'explode') { - return 'end'; - } else { - return 'middle'; + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = this.data.series.filter(function(val) { + return val !== 0; + }).length === 1; + + // Draw the series + // initialize series groups + for (var i = 0; i < this.data.series.length; i++) { + seriesGroups[i] = this.svg.elem('g', null, null, true); + + // If the series is an object and contains a name we add a custom attribute + if(this.data.series[i].name) { + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) + }, Chartist.xmlNs.uri); } - } - /** - * Creates the pie chart - * - * @param options - */ - function createChart(options) { - var seriesGroups = [], - chartRect, - radius, - labelRadius, - totalDataSum, - startAngle = options.startAngle, - dataArray = Chartist.getDataArray(this.data, options.reverseData); - - // Create SVG.js draw - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); - // Calculate charting rect - chartRect = Chartist.createChartRect(this.svg, options, 0, 0); - // Get biggest circle radius possible within chartRect - radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); - // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { - return previousValue + currentValue; - }, 0); - - // 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 ? options.donutWidth / 2 : 0; - - // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius - // see https://github.com/gionkunz/chartist-js/issues/21 - labelRadius = options.donut ? radius : radius / 2; - // Add the offset to the labelRadius where a negative offset means closed to the center of the chart - labelRadius += options.labelOffset; - - // Calculate end angle based on total sum and current data value and offset with padding - var center = { - x: chartRect.x1 + chartRect.width() / 2, - y: chartRect.y2 + chartRect.height() / 2 - }; + // Use series class from series data or if not set generate one + seriesGroups[i].addClass([ + options.classNames.series, + (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + ].join(' ')); + + var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle + // with Z and use 359.99 degrees + if(endAngle - startAngle === 360) { + endAngle -= 0.01; + } - // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = this.data.series.filter(function(val) { - return val !== 0; - }).length === 1; - - // Draw the series - // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { - seriesGroups[i] = this.svg.elem('g', null, null, true); - - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) - }, Chartist.xmlNs.uri); - } + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), + arcSweep = endAngle - startAngle <= 180 ? '0' : '1', + d = [ + // Start at the end point from the cartesian coordinates + 'M', end.x, end.y, + // Draw arc + 'A', radius, radius, 0, arcSweep, 0, start.x, start.y + ]; - // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ - options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) - ].join(' ')); - - var endAngle = startAngle + dataArray[i] / totalDataSum * 360; - // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle - // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; - } + // If regular pie chart (no donut) we add a line to the center of the circle for completing the pie + if(options.donut === false) { + d.push('L', center.x, center.y); + } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), - end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), - arcSweep = endAngle - startAngle <= 180 ? '0' : '1', - d = [ - // Start at the end point from the cartesian coordinates - 'M', end.x, end.y, - // Draw arc - 'A', radius, radius, 0, arcSweep, 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 === false) { - d.push('L', center.x, center.y); - } + // Create the SVG path + // If this is a donut chart we add the donut class, otherwise just a regular slice + var path = seriesGroups[i].elem('path', { + d: d.join(' ') + }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); - // Create the SVG path - // If this is a donut chart we add the donut class, otherwise just a regular slice - var path = seriesGroups[i].elem('path', { - d: d.join(' ') - }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); + // Adding the pie series value to the path + path.attr({ + 'value': dataArray[i] + }, Chartist.xmlNs.uri); - // Adding the pie series value to the path + // If this is a donut, we add the stroke-width as style attribute + if(options.donut === true) { path.attr({ - 'value': dataArray[i] - }, Chartist.xmlNs.uri); + 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' + }); + } - // If this is a donut, we add the stroke-width as style attribute - if(options.donut === true) { - path.attr({ - 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' - }); - } + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'slice', + value: dataArray[i], + totalDataSum: totalDataSum, + index: i, + group: seriesGroups[i], + element: path, + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + + // If we need to show labels we need to add the label for this slice now + if(options.showLabel) { + // Position at the labelRadius distance from center and between start and end angle + var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), + interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + + var labelElement = seriesGroups[i].elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); // Fire off draw event this.eventEmitter.emit('draw', { - type: 'slice', - value: dataArray[i], - totalDataSum: totalDataSum, + type: 'label', index: i, group: seriesGroups[i], - element: path, - center: center, - radius: radius, - startAngle: startAngle, - endAngle: endAngle + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y }); - - // If we need to show labels we need to add the label for this slice now - if(options.showLabel) { - // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); - - var labelElement = seriesGroups[i].elem('text', { - dx: labelPosition.x, - dy: labelPosition.y, - 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) - }, options.classNames.label).text('' + interpolatedValue); - - // Fire off draw event - this.eventEmitter.emit('draw', { - type: 'label', - index: i, - group: seriesGroups[i], - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y - }); - } - - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues - // (except for last slice) - startAngle = endAngle; } - this.eventEmitter.emit('created', { - chartRect: chartRect, - svg: this.svg, - options: options - }); - } - - /** - * This method creates a new pie chart and returns an object that can be used to redraw the chart. - * - * @memberof Chartist.Pie - * @param {String|Node} query A selector query string or directly a DOM element - * @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 objects that contain a data property with the value and a className property to override the CSS class name for the series group. - * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. - * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] - * @return {Object} An object with a version and an update method to manually redraw the chart - * - * @example - * // Simple pie chart example with four series - * new Chartist.Pie('.ct-chart', { - * series: [10, 2, 4, 3] - * }); - * - * @example - * // Drawing a donut chart - * new Chartist.Pie('.ct-chart', { - * series: [10, 2, 4, 3] - * }, { - * donut: true - * }); - * - * @example - * // Using donut, startAngle and total to draw a gauge chart - * new Chartist.Pie('.ct-chart', { - * series: [20, 10, 30, 40] - * }, { - * donut: true, - * donutWidth: 20, - * startAngle: 270, - * total: 200 - * }); - * - * @example - * // Drawing a pie chart with padding and labels that are outside the pie - * new Chartist.Pie('.ct-chart', { - * series: [20, 10, 30, 40] - * }, { - * chartPadding: 30, - * labelOffset: 50, - * labelDirection: 'explode' - * }); - * - * @example - * // Overriding the class names for individual series - * new Chartist.Pie('.ct-chart', { - * series: [{ - * data: 20, - * className: 'my-custom-class-one' - * }, { - * data: 10, - * className: 'my-custom-class-two' - * }, { - * data: 70, - * className: 'my-custom-class-three' - * }] - * }); - */ - function Pie(query, data, options, responsiveOptions) { - Chartist.Pie.super.constructor.call(this, - query, - data, - Chartist.extend({}, defaultOptions, options), - responsiveOptions); + // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // (except for last slice) + startAngle = endAngle; } - // Creating pie chart type in Chartist namespace - Chartist.Pie = Chartist.Base.extend({ - constructor: Pie, - createChart: createChart, - determineAnchorPosition: determineAnchorPosition + this.eventEmitter.emit('created', { + chartRect: chartRect, + svg: this.svg, + options: options }); + } + + /** + * This method creates a new pie chart and returns an object that can be used to redraw the chart. + * + * @memberof Chartist.Pie + * @param {String|Node} query A selector query string or directly a DOM element + * @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 objects that contain a data property with the value and a className property to override the CSS class name for the series group. + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object with a version and an update method to manually redraw the chart + * + * @example + * // Simple pie chart example with four series + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }); + * + * @example + * // Drawing a donut chart + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }, { + * donut: true + * }); + * + * @example + * // Using donut, startAngle and total to draw a gauge chart + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * donut: true, + * donutWidth: 20, + * startAngle: 270, + * total: 200 + * }); + * + * @example + * // Drawing a pie chart with padding and labels that are outside the pie + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * chartPadding: 30, + * labelOffset: 50, + * labelDirection: 'explode' + * }); + * + * @example + * // Overriding the class names for individual series + * new Chartist.Pie('.ct-chart', { + * series: [{ + * data: 20, + * className: 'my-custom-class-one' + * }, { + * data: 10, + * className: 'my-custom-class-two' + * }, { + * data: 70, + * className: 'my-custom-class-three' + * }] + * }); + */ + function Pie(query, data, options, responsiveOptions) { + Chartist.Pie.super.constructor.call(this, + query, + data, + defaultOptions, + Chartist.extend({}, defaultOptions, options), + responsiveOptions); + } + + // Creating pie chart type in Chartist namespace + Chartist.Pie = Chartist.Base.extend({ + constructor: Pie, + createChart: createChart, + determineAnchorPosition: determineAnchorPosition + }); - }(window, document, Chartist)); +}(window, document, Chartist)); - return Chartist; +return Chartist; })); diff --git a/dist/chartist.min.css b/dist/chartist.min.css index fce5d082..84ff4bdc 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1,7 +1 @@ -/* Chartist.js 0.7.2 - * Copyright © 2015 Gion Kunz - * Free to use under the WTFPL license. - * http://www.wtfpl.net/ - */ - .ct-chart .ct-label,.ct-chart .ct-label.ct-horizontal{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:left}.ct-chart .ct-label.ct-vertical{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:right}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#f4c63d}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#f4c63d}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#d17905}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#d17905}.ct-chart .ct-series.ct-series-e .ct-bar,.ct-chart .ct-series.ct-series-e .ct-line,.ct-chart .ct-series.ct-series-e .ct-point,.ct-chart .ct-series.ct-series-e .ct-slice.ct-donut{stroke:#453d3f}.ct-chart .ct-series.ct-series-e .ct-area,.ct-chart .ct-series.ct-series-e .ct-slice:not(.ct-donut){fill:#453d3f}.ct-chart .ct-series.ct-series-f .ct-bar,.ct-chart .ct-series.ct-series-f .ct-line,.ct-chart .ct-series.ct-series-f .ct-point,.ct-chart .ct-series.ct-series-f .ct-slice.ct-donut{stroke:#59922b}.ct-chart .ct-series.ct-series-f .ct-area,.ct-chart .ct-series.ct-series-f .ct-slice:not(.ct-donut){fill:#59922b}.ct-chart .ct-series.ct-series-g .ct-bar,.ct-chart .ct-series.ct-series-g .ct-line,.ct-chart .ct-series.ct-series-g .ct-point,.ct-chart .ct-series.ct-series-g .ct-slice.ct-donut{stroke:#0544d3}.ct-chart .ct-series.ct-series-g .ct-area,.ct-chart .ct-series.ct-series-g .ct-slice:not(.ct-donut){fill:#0544d3}.ct-chart .ct-series.ct-series-h .ct-bar,.ct-chart .ct-series.ct-series-h .ct-line,.ct-chart .ct-series.ct-series-h .ct-point,.ct-chart .ct-series.ct-series-h .ct-slice.ct-donut{stroke:#6b0392}.ct-chart .ct-series.ct-series-h .ct-area,.ct-chart .ct-series.ct-series-h .ct-slice:not(.ct-donut){fill:#6b0392}.ct-chart .ct-series.ct-series-i .ct-bar,.ct-chart .ct-series.ct-series-i .ct-line,.ct-chart .ct-series.ct-series-i .ct-point,.ct-chart .ct-series.ct-series-i .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-i .ct-area,.ct-chart .ct-series.ct-series-i .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-j .ct-bar,.ct-chart .ct-series.ct-series-j .ct-line,.ct-chart .ct-series.ct-series-j .ct-point,.ct-chart .ct-series.ct-series-j .ct-slice.ct-donut{stroke:#dda458}.ct-chart .ct-series.ct-series-j .ct-area,.ct-chart .ct-series.ct-series-j .ct-slice:not(.ct-donut){fill:#dda458}.ct-chart .ct-series.ct-series-k .ct-bar,.ct-chart .ct-series.ct-series-k .ct-line,.ct-chart .ct-series.ct-series-k .ct-point,.ct-chart .ct-series.ct-series-k .ct-slice.ct-donut{stroke:#eacf7d}.ct-chart .ct-series.ct-series-k .ct-area,.ct-chart .ct-series.ct-series-k .ct-slice:not(.ct-donut){fill:#eacf7d}.ct-chart .ct-series.ct-series-l .ct-bar,.ct-chart .ct-series.ct-series-l .ct-line,.ct-chart .ct-series.ct-series-l .ct-point,.ct-chart .ct-series.ct-series-l .ct-slice.ct-donut{stroke:#86797d}.ct-chart .ct-series.ct-series-l .ct-area,.ct-chart .ct-series.ct-series-l .ct-slice:not(.ct-donut){fill:#86797d}.ct-chart .ct-series.ct-series-m .ct-bar,.ct-chart .ct-series.ct-series-m .ct-line,.ct-chart .ct-series.ct-series-m .ct-point,.ct-chart .ct-series.ct-series-m .ct-slice.ct-donut{stroke:#b2c326}.ct-chart .ct-series.ct-series-m .ct-area,.ct-chart .ct-series.ct-series-m .ct-slice:not(.ct-donut){fill:#b2c326}.ct-chart .ct-series.ct-series-n .ct-bar,.ct-chart .ct-series.ct-series-n .ct-line,.ct-chart .ct-series.ct-series-n .ct-point,.ct-chart .ct-series.ct-series-n .ct-slice.ct-donut{stroke:#6188e2}.ct-chart .ct-series.ct-series-n .ct-area,.ct-chart .ct-series.ct-series-n .ct-slice:not(.ct-donut){fill:#6188e2}.ct-chart .ct-series.ct-series-o .ct-bar,.ct-chart .ct-series.ct-series-o .ct-line,.ct-chart .ct-series.ct-series-o .ct-point,.ct-chart .ct-series.ct-series-o .ct-slice.ct-donut{stroke:#a748ca}.ct-chart .ct-series.ct-series-o .ct-area,.ct-chart .ct-series.ct-series-o .ct-slice:not(.ct-donut){fill:#a748ca}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/dist/chartist.min.js b/dist/chartist.min.js index df6e1d07..a77fb6bb 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.7.2 +/* Chartist.js 0.7.3 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend(a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-2*b.chartPadding-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(f);return i},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){var d=b.axisY?b.axisY.offset||0:0,e=b.axisX?b.axisX.offset||0:0,f=c.stripUnit(b.width)||a.width(),g=c.stripUnit(b.height)||a.height();return{x1:b.chartPadding+d,y1:Math.max(g-b.chartPadding-e,b.chartPadding),x2:Math.max(f-b.chartPadding,b.chartPadding+d),y2:b.chartPadding,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(){var b=h;if(h=c.extend({},j),d)for(i=0;id;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4===d?f[3]={x:+a[0],y:+a[1]}:e-2===d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4===d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}}(window,document,a),function(a,b,c){"use strict";c.Interpolation={},c.Interpolation.none=function(){return function(a){for(var b=(new c.Svg.Path).move(a[0],a[1]),d=3;dg;g+=2){var i=[{x:+a[g-2],y:+a[g-1]},{x:+a[g],y:+a[g+1]},{x:+a[g+2],y:+a[g+3]},{x:+a[g+4],y:+a[g+5]}];b?g?h-4===g?i[3]={x:+a[0],y:+a[1]}:h-2===g&&(i[2]={x:+a[0],y:+a[1]},i[3]={x:+a[2],y:+a[3]}):i[0]={x:+a[h-2],y:+a[h-1]}:h-4===g?i[3]=i[2]:g||(i[0]={x:+a[g],y:+a[g+1]}),f.curve(d*(-i[0].x+6*i[1].x+i[2].x)/6+e*i[2].x,d*(-i[0].y+6*i[1].y+i[2].y)/6+e*i[2].y,d*(i[1].x+6*i[2].x-i[3].x)/6+e*i[2].x,d*(i[1].y+6*i[2].y-i[3].y)/6+e*i[2].y,i[2].x,i[2].y)}return f}}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;ca.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,g,h=[],i=a.startAngle,j=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,0,0),e=Math.min(b.width()/2,b.height()/2),g=a.total||j.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var k={x:b.x1+b.width()/2,y:b.y2+b.height()/2},l=1===this.data.series.filter(function(a){return 0!==a}).length,m=0;m=n-i?"0":"1",r=["M",p.x,p.y,"A",e,e,0,q,0,o.x,o.y];a.donut===!1&&r.push("L",k.x,k.y);var s=h[m].elem("path",{d:r.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:j[m]},c.xmlNs.uri),a.donut===!0&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j[m],totalDataSum:g,index:m,group:h[m],element:s,center:k,radius:e,startAngle:i,endAngle:n}),a.showLabel){var t=c.polarToCartesian(k.x,k.y,f,i+(n-i)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[m]:j[m],m),v=h[m].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(k,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:m,group:h[m],element:v,text:""+u,x:t.x,y:t.y})}i=n}this.eventEmitter.emit("created",{chartRect:b,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie["super"].constructor.call(this,a,b,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(c.roundWithPrecision(f));return i},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.axisY?b.axisY.offset||0:0,f=b.axisX?b.axisX.offset||0:0,g=c.stripUnit(b.width)||a.width(),h=c.stripUnit(b.height)||a.height(),i=c.normalizePadding(b.chartPadding,d);return{x1:i.left+e,y1:Math.max(h-i.bottom-f,i.bottom),x2:Math.max(g-i.right,i.right+e),y2:i.top,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(b){var f=h;if(h=c.extend({},j),d)for(i=0;ig;g+=2){var i=[{x:+a[g-2],y:+a[g-1]},{x:+a[g],y:+a[g+1]},{x:+a[g+2],y:+a[g+3]},{x:+a[g+4],y:+a[g+5]}];b?g?h-4===g?i[3]={x:+a[0],y:+a[1]}:h-2===g&&(i[2]={x:+a[0],y:+a[1]},i[3]={x:+a[2],y:+a[3]}):i[0]={x:+a[h-2],y:+a[h-1]}:h-4===g?i[3]=i[2]:g||(i[0]={x:+a[g],y:+a[g+1]}),f.curve(d*(-i[0].x+6*i[1].x+i[2].x)/6+e*i[2].x,d*(-i[0].y+6*i[1].y+i[2].y)/6+e*i[2].y,d*(i[1].x+6*i[2].x-i[3].x)/6+e*i[2].x,d*(i[1].y+6*i[2].y-i[3].y)/6+e*i[2].y,i[2].x,i[2].y)}return f}}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;ca.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return 0!==a}).length,n=0;n=o-j?"0":"1",s=["M",q.x,q.y,"A",e,e,0,r,0,p.x,p.y];a.donut===!1&&s.push("L",l.x,l.y);var t=i[n].elem("path",{d:s.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(t.attr({value:k[n]},c.xmlNs.uri),a.donut===!0&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,group:i[n],element:t,center:l,radius:e,startAngle:j,endAngle:o}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(o-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n),w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}j=o}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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/dist/chartist.min.js.map b/dist/chartist.min.js.map index b3f01d4d..1b961dfa 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","returnExportsGlobal","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","pow","ceil","step","numberOfSteps","round","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","yOffset","axisY","xOffset","w","h","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":26858,"pos":26844,"col":12,"line":747,"value":"currentOptions","type":"name"},"name":"currentOptions"},"catmullRom2bezier","crp","z","d","iLen","p","Interpolation","none","pathCoordinates","path","Path","move","line","simple","defaultOptions","divisor","prevX","prevY","currX","currY","curve","cardinal","tension","t","c","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","extendObjects","initializeTimeoutId","createChart","detach","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","position","count","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","m","l","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","valueIndex","showPoint","point","showLine","showArea","smoothing","lineSmooth","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], function () {\n return (root.returnExportsGlobal = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like enviroments 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.7.2\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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 */\n var Chartist = {\n version: '0.7.1'\n };\n\n (function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\n };\n\n /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || svg.height()) - (options.chartPadding * 2) - 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(i);\n }\n\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 {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 * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options) {\n var yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height();\n\n return {\n x1: options.chartPadding + yOffset,\n y1: Math.max(h - options.chartPadding - xOffset, options.chartPadding),\n x2: Math.max(w - options.chartPadding, options.chartPadding + yOffset),\n y2: options.chartPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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() {\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) {\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 so we get the correct options\n updateCurrentOptions();\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\n\n //http://schepers.cc/getting-to-the-point\n Chartist.catmullRom2bezier = function (crp, z) {\n var d = [];\n for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +crp[i - 2], y: +crp[i - 1]},\n {x: +crp[i], y: +crp[i + 1]},\n {x: +crp[i + 2], y: +crp[i + 3]},\n {x: +crp[i + 4], y: +crp[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +crp[0], y: +crp[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +crp[0], y: +crp[1]};\n p[3] = {x: +crp[2], y: +crp[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +crp[i], y: +crp[i + 1]};\n }\n }\n d.push(\n [\n (-p[0].x + 6 * p[1].x + p[2].x) / 6,\n (-p[0].y + 6 * p[1].y + p[2].y) / 6,\n (p[1].x + 6 * p[2].x - p[3].x) / 6,\n (p[1].y + 6 * p[2].y - p[3].y) / 6,\n p[2].x,\n p[2].y\n ]\n );\n }\n\n return d;\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function cardinal(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 3; i < pathCoordinates.length; i += 2) {\n path.line(pathCoordinates[i - 1], pathCoordinates[i]);\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 * })\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 };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2],\n prevY = pathCoordinates[i - 1],\n currX = pathCoordinates[i],\n currY = pathCoordinates[i + 1],\n length = (currX - prevX) * d;\n\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY\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 * })\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 };\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) {\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]),\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 );\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} [extendObjects] If set to true, the passed options will be used to extend the options that have been configured already.\n * @memberof Chartist.Base\n */\n function update(data, options, extendObjects) {\n if(data) {\n this.data = data;\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({}, extendObjects ? this.options : {}, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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 options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data;\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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n }(window, document, Chartist));\n ;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n }(window, document, Chartist));\n ;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n /* global Chartist */\n (function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 // 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\n chartPadding: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var smoothing = typeof options.lineSmooth === 'function' ?\n options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()),\n path = smoothing(pathCoordinates);\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 adition 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 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 // 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: 40\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 // 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 },\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 // Padding of the chart drawing area to the container element and labels\n chartPadding: 5,\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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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);\n\n var valueAxis,\n labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.chartPadding + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 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\n chartPadding: 5,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, 0, 0);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\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\n return Chartist;\n\n}));\n"]} \ No newline at end of file +{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","ceil","step","numberOfSteps","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","fallbackPadding","yOffset","axisY","xOffset","w","h","normalizedPadding","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27794,"pos":27780,"col":10,"line":794,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27794,"pos":27780,"col":10,"line":794,"value":"currentOptions","type":"name"},"name":"currentOptions"},"Interpolation","none","pathCoordinates","path","Path","move","line","simple","defaultOptions","divisor","d","prevX","prevY","currX","currY","curve","cardinal","tension","t","c","z","iLen","p","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","position","count","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","m","l","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","valueIndex","showPoint","point","showLine","showArea","smoothing","lineSmooth","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.7.3\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.7.3'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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 yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height(),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding);\n\n return {\n x1: normalizedPadding.left + yOffset,\n y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom),\n x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset),\n y2: normalizedPadding.top,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function cardinal(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 3; i < pathCoordinates.length; i += 2) {\n path.line(pathCoordinates[i - 1], pathCoordinates[i]);\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 * })\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 };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2],\n prevY = pathCoordinates[i - 1],\n currX = pathCoordinates[i],\n currY = pathCoordinates[i + 1],\n length = (currX - prevX) * d;\n\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY\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 * })\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 };\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) {\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]),\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 );\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 // 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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 // 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: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var smoothing = typeof options.lineSmooth === 'function' ?\n options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()),\n path = smoothing(pathCoordinates);\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 adition 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 // 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: 40\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 // 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 },\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 // 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 // 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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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 labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-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/package.json b/package.json index 00cc6c7f..bdec0b34 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.7.2", + "version": "0.7.3", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 1b1f07b429e2c54f598c38c9af99b173d0f5d4d1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 2 Mar 2015 17:44:31 +0100 Subject: [PATCH 196/593] Added accessibility plugin to documentation site and refactored a few examples with chartPadding --- bower.json | 8 +++- site/data/pages/plugins.yml | 40 +++++++++++++++++++ .../examples/example-line-simple-smoothing.js | 7 +++- site/examples/example-plugin-accessibility.js | 36 +++++++++++++++++ site/examples/simple-line-chart.js | 7 +++- site/layouts/default.hbs | 1 + 6 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 site/examples/example-plugin-accessibility.js diff --git a/bower.json b/bower.json index bd842412..c1391b1e 100644 --- a/bower.json +++ b/bower.json @@ -13,7 +13,8 @@ "codemirror": "~4.12.0", "base64": "~0.3.0", "chartist-plugin-pointlabels": "~0.0.2", - "chartist-plugin-sketchy": "~0.0.1" + "chartist-plugin-sketchy": "~0.0.1", + "chartist-plugin-accessibility": "~0.0.1" }, "ignore": [ ".*", @@ -25,5 +26,8 @@ "site", "src", "test" - ] + ], + "resolutions": { + "chartist": "~0.7.3" + } } diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 458a44da..1ebfdd87 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -55,6 +55,46 @@ sections: pull request for this page and add your plugin to the list. + - type: sub-section + data: + title: Accessibility Plugin + level: 4 + items: + - type: text + data: + text: > + 285 million people are estimated to be visually impaired worldwide: 39 million are blind and 246 have low vision. + We should stop the discrimination against our fellow human and, by fairly little effort and following best + practices, make our content on the web accessible. + - type: text + data: + text: > + The accessibility plugin makes your chart accessible for blind people. It automatically generates + visually hidden accessibility tables that allow you to describe your chart for blind people easily. + This plugin was tested with NVDA and JAWS, and provides all necessary things for building an accessible chart. + - type: text + data: + text: > + By simply including this plugin with default configurations you will already make your charts + accessible to blind people! If you put in 5 minutes effort in customizing the configuration with + meaningful content, you will actually even make them enjoy your charts! + - type: live-example + data: + id: example-plugin-accessibility + classes: ct-golden-section + intro: > + Creating an accessible chart that shows some fiscal year figures. This example overrides the visuallyHiddenStyles + configuration property so you can actually see the "invisible" table. + - type: table + data: + rows: + - + - 'Author:' + - Gion Kunz + - + - 'Link:' + - 'chartist-plugin-accessibility' + - type: sub-section data: title: Point Label Plugin diff --git a/site/examples/example-line-simple-smoothing.js b/site/examples/example-line-simple-smoothing.js index caea4677..99c0abb6 100644 --- a/site/examples/example-line-simple-smoothing.js +++ b/site/examples/example-line-simple-smoothing.js @@ -1,8 +1,8 @@ var chart = new Chartist.Line('.ct-chart', { labels: [1, 2, 3, 4, 5], series: [ - [1, 5, 10, 0, 1, 2], - [10, 15, 0, 1, 2, 3] + [1, 5, 10, 0, 1], + [10, 15, 0, 1, 2] ] }, { // Remove this configuration to see that chart rendered with cardinal spline interpolation @@ -11,5 +11,8 @@ var chart = new Chartist.Line('.ct-chart', { divisor: 2 }), fullWidth: true, + chartPadding: { + right: 20 + }, low: 0 }); diff --git a/site/examples/example-plugin-accessibility.js b/site/examples/example-plugin-accessibility.js new file mode 100644 index 00000000..620d1fe5 --- /dev/null +++ b/site/examples/example-plugin-accessibility.js @@ -0,0 +1,36 @@ +new Chartist.Line('.ct-chart', { + labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + series: [ + {name: 'Income', data: [20000, 30000, 35000, 32000, 40000, 42000, 50000, 62000, 80000, 94000, 100000, 120000]}, + {name: 'Expenses', data: [10000, 15000, 12000, 14000, 20000, 23000, 22000, 24000, 21000, 18000, 30000, 32000]} + ] +}, { + fullWidth: true, + lineSmooth: false, + chartPadding: { + right: 20, + left: 10 + }, + axisX: { + labelInterpolationFnc: function(value) { + return value.split('').slice(0, 3).join(''); + } + }, + plugins: [ + Chartist.plugins.ctAccessibility({ + caption: 'Fiscal year 2015', + seriesHeader: 'business numbers', + summary: 'A graphic that shows the business numbers of the fiscal year 2015', + valueTransform: function(value) { + return value + ' dollar'; + }, + // ONLY USE THIS IF YOU WANT TO MAKE YOUR ACCESSIBILITY TABLE ALSO VISIBLE! + visuallyHiddenStyles: 'position: absolute; top: 100%; width: 100%; font-size: 11px; overflow-x: auto; background-color: rgba(0, 0, 0, 0.1); padding: 10px' + }) + ] +}); + +// This is only used for the example on the Chartist example page +$chart.parent().css({ + 'margin-bottom': '160px' +}); diff --git a/site/examples/simple-line-chart.js b/site/examples/simple-line-chart.js index bffe7c3a..0b5c4742 100644 --- a/site/examples/simple-line-chart.js +++ b/site/examples/simple-line-chart.js @@ -5,4 +5,9 @@ new Chartist.Line('.ct-chart', { [2, 1, 3.5, 7, 3], [1, 3, 4, 5, 6] ] -}); \ No newline at end of file +}, { + fullWidth: true, + chartPadding: { + right: 40 + } +}); diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 019bb689..0f017332 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -68,6 +68,7 @@ + From 7c30152eea569a7346deabd03ce67f51212a5265 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 2 Mar 2015 17:49:18 +0100 Subject: [PATCH 197/593] Refactored live example code evaluation to include emptying previous container content --- site/scripts/main.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/site/scripts/main.js b/site/scripts/main.js index 875adac9..df5a0c6f 100644 --- a/site/scripts/main.js +++ b/site/scripts/main.js @@ -12,9 +12,14 @@ function evalChartistCode(code, chartElement) { // Remove any declaration of $chart as we are passing $chart to our function eval modified = modified.replace(/var \$chart.+;/, ''); + if(chartElement.__chartist__) { + chartElement.__chartist__.detach(); + } + var $chartElement = $(chartElement).empty(); + try { // Create function from the modified code and execute it - return (new Function(['chartElement', '$chart'], modified)(chartElement, $(chartElement))); // jshint ignore:line + return (new Function(['chartElement', '$chart'], modified)(chartElement, $chartElement)); // jshint ignore:line } catch(err) { // Maybe show error in the future } @@ -118,4 +123,4 @@ $(document).foundation({ topbar: { scrolltop: false } -}); \ No newline at end of file +}); From 0452ab52dbe24af0f50876761b714938c31d24a4 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Fri, 6 Mar 2015 17:39:26 +0800 Subject: [PATCH 198/593] Fix minor typo in examples page for bi-polar charts --- site/data/pages/examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 96e1be04..de16cec6 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -100,7 +100,7 @@ sections: id: bi-polar-bar-interpolated classes: ct-golden-section intro: > - A bi-plar bar chart with a range limit set with low and high. There is also an interpolation + A bi-polar bar chart with a range limit set with low and high. There is also an interpolation function used to skip every odd grid line / label. - type: live-example data: From b832b212f4581ba41bd9b6e9648f0736cd9f8bf4 Mon Sep 17 00:00:00 2001 From: Rajiv Bose Date: Tue, 17 Mar 2015 11:01:21 +0000 Subject: [PATCH 199/593] Update to getting-started.yml After completing the `bower install chartist --save` step, the instructions for setting up *THE SASS WAY* includes the wrong bash command. This fix is for the listed path to file `_chartist-settings.scss styles`. --- site/data/pages/getting-started.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 6ac17178..416a8280 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -90,7 +90,7 @@ sections: - type: code data: lang: bash - code: cp bower_components/chartist/libdist/scss/settings/_chartist-settings.scss styles + code: cp bower_components/chartist/dist/scss/settings/_chartist-settings.scss styles - type: text data: From 5fc239a90d4b4b2a32aebf97d6575cd68f7df5c3 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 13:20:41 +0200 Subject: [PATCH 200/593] Documentation, fixed path to Sass settings --- site/data/pages/getting-started.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 416a8280..44105301 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -126,7 +126,7 @@ sections: data: id: default-Sass-settings button: Show default settings - path: site/styles/settings/_chartist-settings.scss + path: src/styles/settings/_chartist-settings.scss lang: scss - title: Create your first chart From 9658e745b3093753088d8a666b8c68c6ed9a51b1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 13:28:20 +0200 Subject: [PATCH 201/593] Added matchMedia polyfill to documentation site and made browser hint more clear --- bower.json | 3 ++- site/data/pages/getting-started.yml | 4 +++- site/layouts/default.hbs | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index c1391b1e..d524aa3a 100644 --- a/bower.json +++ b/bower.json @@ -14,7 +14,8 @@ "base64": "~0.3.0", "chartist-plugin-pointlabels": "~0.0.2", "chartist-plugin-sketchy": "~0.0.1", - "chartist-plugin-accessibility": "~0.0.1" + "chartist-plugin-accessibility": "~0.0.1", + "matchMedia": "~0.2.0" }, "ignore": [ ".*", diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 44105301..c6c2f6f1 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -360,7 +360,9 @@ sections: classes: hint-cross-browser text: > For IE9 you need to use a matchMedia polyfill. You should take a look at - Paul Irish's matchMedia polyfill. + Paul Irish's matchMedia polyfill. Make + sure you include matchMedia.js as well as matchMedia.addListener.js as always both are needed + to polyfill the full specification of window.matchMedia. - title: Advanced level: 3 diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 0f017332..f0f99d1f 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -49,6 +49,8 @@ + + From febd1d944ef2d8d989a80e310316c0775d624342 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 14:04:09 +0200 Subject: [PATCH 202/593] Documentation: Added better example of how to include Chartist in HTML --- site/code-snippets/simple-start.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/site/code-snippets/simple-start.html b/site/code-snippets/simple-start.html index 465211fd..5b8c524f 100644 --- a/site/code-snippets/simple-start.html +++ b/site/code-snippets/simple-start.html @@ -1,7 +1,12 @@ - - + My first Chartist Tests + + + + + From b23179f208758c8ec402f0dee0319f526b9d3a34 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 14:04:59 +0200 Subject: [PATCH 203/593] Documentation: Added example on how to include two charts on a page --- site/code-snippets/two-charts.html | 16 ++++++++++++++++ site/data/pages/getting-started.yml | 17 +++++++++++++++++ site/styles/_highlight.scss | 10 ---------- 3 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 site/code-snippets/two-charts.html diff --git a/site/code-snippets/two-charts.html b/site/code-snippets/two-charts.html new file mode 100644 index 00000000..07a4cd55 --- /dev/null +++ b/site/code-snippets/two-charts.html @@ -0,0 +1,16 @@ +
    +
    + + diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index c6c2f6f1..4906a928 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -284,6 +284,23 @@ sections: id: simple-start-fixed-chart lang: js + - type: sub-section + data: + title: More than one chart on my page? + level: 5 + items: + - type: text + data: + text: > + The example above uses the chartist default class to select the element where the chart should + be created. This class is important for applying the right styles in the CSS of Chartist. If + you need to create individual charts on one page, you should use IDs to initialize them separately. + + - type: code-snippet + data: + id: two-charts + lang: html + - type: sub-section data: title: The configuration of your chart diff --git a/site/styles/_highlight.scss b/site/styles/_highlight.scss index 2d12f642..407e08c0 100644 --- a/site/styles/_highlight.scss +++ b/site/styles/_highlight.scss @@ -118,13 +118,3 @@ Chartist style - Licensed under WTFPL by Gion Kunz https://github.com/gionkunz/c .hljs-status { font-weight: bold; } - -.coffeescript .javascript, -.javascript .xml, -.tex .hljs-formula, -.xml .javascript, -.xml .vbscript, -.xml .css, -.xml .hljs-cdata { - opacity: 0.5; -} From 161a367b4306b567db2da1d7ea97b407654ff9a7 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 20:15:52 +0200 Subject: [PATCH 204/593] Added arc to Svg.Path API and refactored pie.js to use Svg.Path as implemented in #204 --- src/scripts/charts/pie.js | 28 +++++++++++++--------------- src/scripts/svg-path.js | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 31d9dcec..22954db4 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -143,34 +143,31 @@ } var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), - end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), - arcSweep = endAngle - startAngle <= 180 ? '0' : '1', - d = [ - // Start at the end point from the cartesian coordinates - 'M', end.x, end.y, - // Draw arc - 'A', radius, radius, 0, arcSweep, 0, start.x, start.y - ]; + end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); + + var path = new Chartist.Svg.Path() + .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 === false) { - d.push('L', center.x, center.y); + if(!options.donut) { + path.line(center.x, center.y); } // Create the SVG path // If this is a donut chart we add the donut class, otherwise just a regular slice - var path = seriesGroups[i].elem('path', { - d: d.join(' ') + var pathElement = seriesGroups[i].elem('path', { + d: path.stringify() }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); // Adding the pie series value to the path - path.attr({ + pathElement.attr({ 'value': dataArray[i] }, Chartist.xmlNs.uri); // If this is a donut, we add the stroke-width as style attribute if(options.donut === true) { - path.attr({ + pathElement.attr({ 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' }); } @@ -182,7 +179,8 @@ totalDataSum: totalDataSum, index: i, group: seriesGroups[i], - element: path, + element: pathElement, + path: path.clone(), center: center, radius: radius, startAngle: startAngle, diff --git a/src/scripts/svg-path.js b/src/scripts/svg-path.js index cbaaba06..f0f0e6d3 100644 --- a/src/scripts/svg-path.js +++ b/src/scripts/svg-path.js @@ -16,7 +16,8 @@ var elementDescriptions = { m: ['x', 'y'], l: ['x', 'y'], - c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'] + c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'], + a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y'] }; /** @@ -63,7 +64,7 @@ * 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. * * @memberof Chartist.Svg.Path - * @param {Number} [position] If a number is passed then the cursor is set to this position in the path element array. + * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array. * @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. */ function position(pos) { @@ -93,7 +94,7 @@ * @memberof Chartist.Svg.Path * @param {Number} x The x coordinate for the move element. * @param {Number} y The y coordinate for the move element. - * @param {Boolean} relative If set to true the move element will be created with relative coordinates (lowercase letter) + * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter) * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function move(x, y, relative) { @@ -110,7 +111,7 @@ * @memberof Chartist.Svg.Path * @param {Number} x The x coordinate for the line element. * @param {Number} y The y coordinate for the line element. - * @param {Boolean} relative If set to true the line element will be created with relative coordinates (lowercase letter) + * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter) * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function line(x, y, relative) { @@ -131,7 +132,7 @@ * @param {Number} y2 The y coordinate for the second control point of the bezier curve. * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. - * @param {Boolean} relative If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function curve(x1, y1, x2, y2, x, y, relative) { @@ -146,6 +147,33 @@ return this; } + /** + * Use this function to add a new non-bezier curve SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} rx The radius to be used for the x-axis of the arc. + * @param {Number} ry The radius to be used for the y-axis of the arc. + * @param {Number} xAr Defines the orientation of the arc + * @param {Number} lAf Large arc flag + * @param {Number} sf Sweep flag + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function arc(rx, ry, xAr, lAf, sf, x, y, relative) { + element('A', { + rx: +rx, + ry: +ry, + xAr: +xAr, + lAf: +lAf, + sf: +sf, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + /** * 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. * @@ -291,6 +319,7 @@ move: move, line: line, curve: curve, + arc: arc, scale: scale, translate: translate, transform: transform, From 91d692e38503c9abebb22910dfa629aff81903a3 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 20:37:02 +0200 Subject: [PATCH 205/593] Modified watch task to deep watch js files --- tasks/watch.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/watch.js b/tasks/watch.js index bf3fbc13..69bb773a 100644 --- a/tasks/watch.js +++ b/tasks/watch.js @@ -21,8 +21,8 @@ module.exports = function (grunt) { }, js: { files: [ - '<%= pkg.config.site %>/scripts/{,*/}*.js', - '<%= pkg.config.src %>/{,*/}*.js' + '<%= pkg.config.site %>/scripts/**/*.js', + '<%= pkg.config.src %>/scripts/**/*.js' ], tasks: ['newer:jshint:all'], options: { From a8f4cc66181c6fa9e82150c4f2918fd740e02869 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 20:37:29 +0200 Subject: [PATCH 206/593] Closing path of Pie if not a donut for correct strokes --- src/scripts/charts/pie.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 22954db4..471c45f6 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -145,7 +145,8 @@ var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); - var path = new Chartist.Svg.Path() + // 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) .move(end.x, end.y) .arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y); @@ -166,7 +167,7 @@ }, Chartist.xmlNs.uri); // If this is a donut, we add the stroke-width as style attribute - if(options.donut === true) { + if(options.donut) { pathElement.attr({ 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' }); From af950904965a5ab2f9efb883f6b1d3f3237b7c46 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 29 Mar 2015 21:12:10 +0200 Subject: [PATCH 207/593] Exposing axis objects in created event that makes it easier to draw addition things onto the existing chart, fixes #249 --- src/scripts/charts/bar.js | 14 +++++++++----- src/scripts/charts/line.js | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 6cfcfb42..9b03259b 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -111,10 +111,12 @@ var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, - labelAxis; + labelAxis, + axisX, + axisY; if(options.horizontalBars) { - labelAxis = new Chartist.StepAxis( + labelAxis = axisY = new Chartist.StepAxis( Chartist.Axis.units.y, chartRect, function timeAxisTransform(projectedValue) { @@ -131,7 +133,7 @@ } ); - valueAxis = new Chartist.LinearScaleAxis( + valueAxis = axisX = new Chartist.LinearScaleAxis( Chartist.Axis.units.x, chartRect, function valueAxisTransform(projectedValue) { @@ -149,7 +151,7 @@ } ); } else { - labelAxis = new Chartist.StepAxis( + labelAxis = axisX = new Chartist.StepAxis( Chartist.Axis.units.x, chartRect, function timeAxisTransform(projectedValue) { @@ -165,7 +167,7 @@ } ); - valueAxis = new Chartist.LinearScaleAxis( + valueAxis = axisY = new Chartist.LinearScaleAxis( Chartist.Axis.units.y, chartRect, function valueAxisTransform(projectedValue) { @@ -278,6 +280,8 @@ this.eventEmitter.emit('created', { bounds: valueAxis.bounds, chartRect: chartRect, + axisX: axisX, + axisY: axisY, svg: this.svg, options: options }); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 821535f2..eb166eee 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -283,6 +283,8 @@ this.eventEmitter.emit('created', { bounds: axisY.bounds, chartRect: chartRect, + axisX: axisX, + axisY: axisY, svg: this.svg, options: options }); From c766ab7b2d1aaf923a9107b8c9db85c545f6d5a5 Mon Sep 17 00:00:00 2001 From: Globegitter Date: Thu, 16 Apr 2015 18:42:13 +0100 Subject: [PATCH 208/593] Added tooltip plugin to examples. --- bower.json | 1 + site/data/pages/plugins.yml | 33 +++++++++++++++++++++++++ site/examples/example-plugin-tooltip.js | 18 ++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 site/examples/example-plugin-tooltip.js diff --git a/bower.json b/bower.json index d524aa3a..5ad11e70 100644 --- a/bower.json +++ b/bower.json @@ -15,6 +15,7 @@ "chartist-plugin-pointlabels": "~0.0.2", "chartist-plugin-sketchy": "~0.0.1", "chartist-plugin-accessibility": "~0.0.1", + "chartist-plugin-tooltip": "~0.0.8", "matchMedia": "~0.2.0" }, "ignore": [ diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 1ebfdd87..d3d0b5ae 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -95,6 +95,39 @@ sections: - 'Link:' - 'chartist-plugin-accessibility' + + - type: sub-section + data: + title: Tooltip Plugin + level: 4 + items: + - type: text + data: + text: > + The tooltip plugin makes it super simple to add tooltips to most of your charts which can often + increase it's usability. + - type: text + data: + text: > + By simply including this plugin with default configurations you will already make your charts + get some tooltips showing. + - type: live-example + data: + id: example-plugin-tooltip + classes: ct-golden-section + intro: > + Creating a simple line chart showing how the tooltips work. + - type: table + data: + rows: + - + - 'Author:' + - Markus Padourek + - + - 'Link:' + - 'chartist-plugin-tooltip' + + - type: sub-section data: title: Point Label Plugin diff --git a/site/examples/example-plugin-tooltip.js b/site/examples/example-plugin-tooltip.js new file mode 100644 index 00000000..5299731d --- /dev/null +++ b/site/examples/example-plugin-tooltip.js @@ -0,0 +1,18 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3], + series: [ + [ + {meta: 'description', value: 1 }, + {meta: 'description', value: 5}, + {meta: 'description', value: 3} + ], + [ + {meta: 'other description', value: 2}, + {meta: 'other description', value: 4}, + {meta: 'other description', value: 2} + ] +}, { + plugins: [ + Chartist.plugins.tooltip() + ] +}); From 0255803dab81ae8a31fb8759d3c446f72a151411 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Apr 2015 19:11:46 +0200 Subject: [PATCH 209/593] Changed grid event to use axis object instead of string --- src/scripts/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 2ff73a2d..eeffc9e9 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -624,7 +624,7 @@ var Chartist = { eventEmitter.emit('draw', Chartist.extend({ type: 'grid', - axis: axis.units.pos, + axis: axis, index: index, group: group, element: gridElement From c56c77bdb77becd1fcbe215eda73733e01df2a12 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Apr 2015 19:27:23 +0200 Subject: [PATCH 210/593] Bumped to 0.7.4 --- CHANGELOG.md | 9 ++++ bower.json | 2 +- dist/chartist.js | 92 +++++++++++++++++++++++++++------------- dist/chartist.min.js | 4 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- 6 files changed, 77 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f95c2b0..28560d8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +v0.7.4 - 19 Apr 2015 +-------------------- +- Enhanced documentation site (Accessibility plugin, live example eval, fixed path to Sass settings, better HTML example of how to include Chartist, example how to include multiple charts on one page) +- Added Arc to Chartist.Svg.Path +- Refactored Chartist.Pie to make use of Svg.Path and expose path in events +- Closing path of Pie if not a donut for correct strokes +- Exposing axis objects in created event +- Changed grid event to use axis object instead of string + v0.7.3 - 27 Feb 2015 -------------------- - Fixed bugs in the chart.update method diff --git a/bower.json b/bower.json index d524aa3a..54d788bd 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.7.3", + "version": "0.7.4", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 45cf6dbf..bf2f10ee 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.7.3 +/* Chartist.js 0.7.4 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.7.3' + version: '0.7.4' }; (function (window, document, Chartist) { @@ -645,7 +645,7 @@ var Chartist = { eventEmitter.emit('draw', Chartist.extend({ type: 'grid', - axis: axis.units.pos, + axis: axis, index: index, group: group, element: gridElement @@ -1949,7 +1949,8 @@ var Chartist = { var elementDescriptions = { m: ['x', 'y'], l: ['x', 'y'], - c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'] + c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'], + a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y'] }; /** @@ -1996,7 +1997,7 @@ var Chartist = { * 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. * * @memberof Chartist.Svg.Path - * @param {Number} [position] If a number is passed then the cursor is set to this position in the path element array. + * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array. * @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. */ function position(pos) { @@ -2026,7 +2027,7 @@ var Chartist = { * @memberof Chartist.Svg.Path * @param {Number} x The x coordinate for the move element. * @param {Number} y The y coordinate for the move element. - * @param {Boolean} relative If set to true the move element will be created with relative coordinates (lowercase letter) + * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter) * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function move(x, y, relative) { @@ -2043,7 +2044,7 @@ var Chartist = { * @memberof Chartist.Svg.Path * @param {Number} x The x coordinate for the line element. * @param {Number} y The y coordinate for the line element. - * @param {Boolean} relative If set to true the line element will be created with relative coordinates (lowercase letter) + * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter) * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function line(x, y, relative) { @@ -2064,7 +2065,7 @@ var Chartist = { * @param {Number} y2 The y coordinate for the second control point of the bezier curve. * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. - * @param {Boolean} relative If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function curve(x1, y1, x2, y2, x, y, relative) { @@ -2079,6 +2080,33 @@ var Chartist = { return this; } + /** + * Use this function to add a new non-bezier curve SVG path element. + * + * @memberof Chartist.Svg.Path + * @param {Number} rx The radius to be used for the x-axis of the arc. + * @param {Number} ry The radius to be used for the y-axis of the arc. + * @param {Number} xAr Defines the orientation of the arc + * @param {Number} lAf Large arc flag + * @param {Number} sf Sweep flag + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @return {Chartist.Svg.Path} The current path object for easy call chaining. + */ + function arc(rx, ry, xAr, lAf, sf, x, y, relative) { + element('A', { + rx: +rx, + ry: +ry, + xAr: +xAr, + lAf: +lAf, + sf: +sf, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative); + return this; + } + /** * 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. * @@ -2224,6 +2252,7 @@ var Chartist = { move: move, line: line, curve: curve, + arc: arc, scale: scale, translate: translate, transform: transform, @@ -2634,6 +2663,8 @@ var Chartist = { this.eventEmitter.emit('created', { bounds: axisY.bounds, chartRect: chartRect, + axisX: axisX, + axisY: axisY, svg: this.svg, options: options }); @@ -2849,10 +2880,12 @@ var Chartist = { var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, - labelAxis; + labelAxis, + axisX, + axisY; if(options.horizontalBars) { - labelAxis = new Chartist.StepAxis( + labelAxis = axisY = new Chartist.StepAxis( Chartist.Axis.units.y, chartRect, function timeAxisTransform(projectedValue) { @@ -2869,7 +2902,7 @@ var Chartist = { } ); - valueAxis = new Chartist.LinearScaleAxis( + valueAxis = axisX = new Chartist.LinearScaleAxis( Chartist.Axis.units.x, chartRect, function valueAxisTransform(projectedValue) { @@ -2887,7 +2920,7 @@ var Chartist = { } ); } else { - labelAxis = new Chartist.StepAxis( + labelAxis = axisX = new Chartist.StepAxis( Chartist.Axis.units.x, chartRect, function timeAxisTransform(projectedValue) { @@ -2903,7 +2936,7 @@ var Chartist = { } ); - valueAxis = new Chartist.LinearScaleAxis( + valueAxis = axisY = new Chartist.LinearScaleAxis( Chartist.Axis.units.y, chartRect, function valueAxisTransform(projectedValue) { @@ -3016,6 +3049,8 @@ var Chartist = { this.eventEmitter.emit('created', { bounds: valueAxis.bounds, chartRect: chartRect, + axisX: axisX, + axisY: axisY, svg: this.svg, options: options }); @@ -3219,34 +3254,32 @@ var Chartist = { } var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), - end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle), - arcSweep = endAngle - startAngle <= 180 ? '0' : '1', - d = [ - // Start at the end point from the cartesian coordinates - 'M', end.x, end.y, - // Draw arc - 'A', radius, radius, 0, arcSweep, 0, start.x, start.y - ]; + end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); + + // 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) + .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 === false) { - d.push('L', center.x, center.y); + if(!options.donut) { + path.line(center.x, center.y); } // Create the SVG path // If this is a donut chart we add the donut class, otherwise just a regular slice - var path = seriesGroups[i].elem('path', { - d: d.join(' ') + var pathElement = seriesGroups[i].elem('path', { + d: path.stringify() }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); // Adding the pie series value to the path - path.attr({ + pathElement.attr({ 'value': dataArray[i] }, Chartist.xmlNs.uri); // If this is a donut, we add the stroke-width as style attribute - if(options.donut === true) { - path.attr({ + if(options.donut) { + pathElement.attr({ 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' }); } @@ -3258,7 +3291,8 @@ var Chartist = { totalDataSum: totalDataSum, index: i, group: seriesGroups[i], - element: path, + element: pathElement, + path: path.clone(), center: center, radius: radius, startAngle: startAngle, diff --git a/dist/chartist.min.js b/dist/chartist.min.js index a77fb6bb..d353e5a6 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,8 @@ -/* Chartist.js 0.7.3 +/* Chartist.js 0.7.4 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(c.roundWithPrecision(f));return i},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.axisY?b.axisY.offset||0:0,f=b.axisX?b.axisX.offset||0:0,g=c.stripUnit(b.width)||a.width(),h=c.stripUnit(b.height)||a.height(),i=c.normalizePadding(b.chartPadding,d);return{x1:i.left+e,y1:Math.max(h-i.bottom-f,i.bottom),x2:Math.max(g-i.right,i.right+e),y2:i.top,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.units.pos,index:b,group:g,element:k},j))},c.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(b){var f=h;if(h=c.extend({},j),d)for(i=0;ig;g+=2){var i=[{x:+a[g-2],y:+a[g-1]},{x:+a[g],y:+a[g+1]},{x:+a[g+2],y:+a[g+3]},{x:+a[g+4],y:+a[g+5]}];b?g?h-4===g?i[3]={x:+a[0],y:+a[1]}:h-2===g&&(i[2]={x:+a[0],y:+a[1]},i[3]={x:+a[2],y:+a[3]}):i[0]={x:+a[h-2],y:+a[h-1]}:h-4===g?i[3]=i[2]:g||(i[0]={x:+a[g],y:+a[g+1]}),f.curve(d*(-i[0].x+6*i[1].x+i[2].x)/6+e*i[2].x,d*(-i[0].y+6*i[1].y+i[2].y)/6+e*i[2].y,d*(i[1].x+6*i[2].x-i[3].x)/6+e*i[2].x,d*(i[1].y+6*i[2].y-i[3].y)/6+e*i[2].y,i[2].x,i[2].y)}return f}}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;ca.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return 0!==a}).length,n=0;n=o-j?"0":"1",s=["M",q.x,q.y,"A",e,e,0,r,0,p.x,p.y];a.donut===!1&&s.push("L",l.x,l.y);var t=i[n].elem("path",{d:s.join(" ")},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(t.attr({value:k[n]},c.xmlNs.uri),a.donut===!0&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,group:i[n],element:t,center:l,radius:e,startAngle:j,endAngle:o}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(o-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n),w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}j=o}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.4"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(c.roundWithPrecision(f));return i},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.axisY?b.axisY.offset||0:0,f=b.axisX?b.axisX.offset||0:0,g=c.stripUnit(b.width)||a.width(),h=c.stripUnit(b.height)||a.height(),i=c.normalizePadding(b.chartPadding,d);return{x1:i.left+e,y1:Math.max(h-i.bottom-f,i.bottom),x2:Math.max(g-i.right,i.right+e),y2:i.top,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(b){var f=h;if(h=c.extend({},j),d)for(i=0;ig;g+=2){var i=[{x:+a[g-2],y:+a[g-1]},{x:+a[g],y:+a[g+1]},{x:+a[g+2],y:+a[g+3]},{x:+a[g+4],y:+a[g+5]}];b?g?h-4===g?i[3]={x:+a[0],y:+a[1]}:h-2===g&&(i[2]={x:+a[0],y:+a[1]},i[3]={x:+a[2],y:+a[3]}):i[0]={x:+a[h-2],y:+a[h-1]}:h-4===g?i[3]=i[2]:g||(i[0]={x:+a[g],y:+a[g+1]}),f.curve(d*(-i[0].x+6*i[1].x+i[2].x)/6+e*i[2].x,d*(-i[0].y+6*i[1].y+i[2].y)/6+e*i[2].y,d*(i[1].x+6*i[2].x-i[3].x)/6+e*i[2].x,d*(i[1].y+6*i[2].y-i[3].y)/6+e*i[2].y,i[2].x,i[2].y)}return f}}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;ca.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return 0!==a}).length,n=0;n180,0,p.x,p.y);a.donut||r.line(l.x,l.y);var s=i[n].elem("path",{d:r.stringify()},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:k[n]},c.xmlNs.uri),a.donut&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,group:i[n],element:s,path:r.clone(),center:l,radius:e,startAngle:j,endAngle:o}),a.showLabel){var t=c.polarToCartesian(l.x,l.y,f,j+(o-j)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n),v=i[n].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(l,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:v,text:""+u,x:t.x,y:t.y})}j=o}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 1b961dfa..58728afd 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","ceil","step","numberOfSteps","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","fallbackPadding","yOffset","axisY","xOffset","w","h","normalizedPadding","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27794,"pos":27780,"col":10,"line":794,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27794,"pos":27780,"col":10,"line":794,"value":"currentOptions","type":"name"},"name":"currentOptions"},"Interpolation","none","pathCoordinates","path","Path","move","line","simple","defaultOptions","divisor","d","prevX","prevY","currX","currY","curve","cardinal","tension","t","c","z","iLen","p","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","position","count","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","m","l","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","valueIndex","showPoint","point","showLine","showArea","smoothing","lineSmooth","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","arcSweep","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.7.3\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.7.3'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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 yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height(),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding);\n\n return {\n x1: normalizedPadding.left + yOffset,\n y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom),\n x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset),\n y2: normalizedPadding.top,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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.units.pos,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function cardinal(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 3; i < pathCoordinates.length; i += 2) {\n path.line(pathCoordinates[i - 1], pathCoordinates[i]);\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 * })\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 };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2],\n prevY = pathCoordinates[i - 1],\n currX = pathCoordinates[i],\n currY = pathCoordinates[i + 1],\n length = (currX - prevX) * d;\n\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY\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 * })\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 };\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) {\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]),\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 );\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 // 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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 };\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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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} [position] 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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 // 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: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var smoothing = typeof options.lineSmooth === 'function' ?\n options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()),\n path = smoothing(pathCoordinates);\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\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 adition 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 // 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: 40\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 // 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 },\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 // 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 // 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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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 labelAxis;\n\n if(options.horizontalBars) {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle),\n arcSweep = endAngle - startAngle <= 180 ? '0' : '1',\n d = [\n // Start at the end point from the cartesian coordinates\n 'M', end.x, end.y,\n // Draw arc\n 'A', radius, radius, 0, arcSweep, 0, start.x, start.y\n ];\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 === false) {\n d.push('L', 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 path = seriesGroups[i].elem('path', {\n d: d.join(' ')\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n path.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut === true) {\n path.attr({\n 'style': 'stroke-width: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\n element: path,\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","ceil","step","numberOfSteps","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","fallbackPadding","yOffset","axisY","xOffset","w","h","normalizedPadding","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27784,"pos":27770,"col":10,"line":794,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27784,"pos":27770,"col":10,"line":794,"value":"currentOptions","type":"name"},"name":"currentOptions"},"Interpolation","none","pathCoordinates","path","Path","move","line","simple","defaultOptions","divisor","d","prevX","prevY","currX","currY","curve","cardinal","tension","t","c","z","iLen","p","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","position","count","arc","rx","ry","xAr","lAf","sf","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","valueIndex","showPoint","point","showLine","showArea","smoothing","lineSmooth","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.7.4\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.7.4'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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 yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height(),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding);\n\n return {\n x1: normalizedPadding.left + yOffset,\n y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom),\n x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset),\n y2: normalizedPadding.top,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function cardinal(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 3; i < pathCoordinates.length; i += 2) {\n path.line(pathCoordinates[i - 1], pathCoordinates[i]);\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 * })\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 };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2],\n prevY = pathCoordinates[i - 1],\n currX = pathCoordinates[i],\n currY = pathCoordinates[i + 1],\n length = (currX - prevX) * d;\n\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY\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 * })\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 };\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) {\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]),\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 );\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 // 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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function arc(rx, ry, xAr, lAf, sf, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 // 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: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var smoothing = typeof options.lineSmooth === 'function' ?\n options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()),\n path = smoothing(pathCoordinates);\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\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 adition 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 // 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: 40\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 // 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 },\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 // 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 // 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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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 labelAxis,\n axisX,\n axisY;\n\n if(options.horizontalBars) {\n labelAxis = axisY = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].elem('path', {\n d: path.stringify()\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-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/package.json b/package.json index bdec0b34..bb7bb227 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.7.3", + "version": "0.7.4", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 4a28aea5bbacf0a76b00ccc5a57f391aa52fac52 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Apr 2015 19:39:10 +0200 Subject: [PATCH 211/593] Fixed example with animation that relies on axis object --- site/examples/example-line-svg-animation.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/site/examples/example-line-svg-animation.js b/site/examples/example-line-svg-animation.js index 7ffe6e02..4a7d746c 100644 --- a/site/examples/example-line-svg-animation.js +++ b/site/examples/example-line-svg-animation.js @@ -88,22 +88,22 @@ chart.on('draw', function(data) { var pos1Animation = { begin: seq * delays, dur: durations, - from: data[data.axis + '1'] - 30, - to: data[data.axis + '1'], + from: data[data.axis.units.pos + '1'] - 30, + to: data[data.axis.units.pos + '1'], easing: 'easeOutQuart' }; var pos2Animation = { begin: seq * delays, dur: durations, - from: data[data.axis + '2'] - 100, - to: data[data.axis + '2'], + from: data[data.axis.units.pos + '2'] - 100, + to: data[data.axis.units.pos + '2'], easing: 'easeOutQuart' }; var animations = {}; - animations[data.axis + '1'] = pos1Animation; - animations[data.axis + '2'] = pos2Animation; + animations[data.axis.units.pos + '1'] = pos1Animation; + animations[data.axis.units.pos + '2'] = pos2Animation; animations['opacity'] = { begin: seq * delays, dur: durations, From 2e67c6a9fac531c46fb398732b0026fc1b2474ca Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Apr 2015 20:14:29 +0200 Subject: [PATCH 212/593] Documentation: Fixed tooltip plugin example code and inclusion --- site/data/pages/plugins.yml | 62 ++++++++++++------------- site/examples/example-plugin-tooltip.js | 4 ++ site/layouts/default.hbs | 1 + 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index d3d0b5ae..b22996c2 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -95,38 +95,36 @@ sections: - 'Link:' - 'chartist-plugin-accessibility' - - - type: sub-section - data: - title: Tooltip Plugin - level: 4 - items: - - type: text - data: - text: > - The tooltip plugin makes it super simple to add tooltips to most of your charts which can often - increase it's usability. - - type: text - data: - text: > - By simply including this plugin with default configurations you will already make your charts - get some tooltips showing. - - type: live-example - data: - id: example-plugin-tooltip - classes: ct-golden-section - intro: > - Creating a simple line chart showing how the tooltips work. - - type: table - data: - rows: - - - - 'Author:' - - Markus Padourek - - - - 'Link:' - - 'chartist-plugin-tooltip' - + - type: sub-section + data: + title: Tooltip Plugin + level: 4 + items: + - type: text + data: + text: > + The tooltip plugin makes it super simple to add tooltips to most of your charts which can often + increase it's usability. + - type: text + data: + text: > + By simply including this plugin with default configurations you will already make your charts + get some tooltips showing. + - type: live-example + data: + id: example-plugin-tooltip + classes: ct-golden-section + intro: > + Creating a simple line chart showing how the tooltips work. + - type: table + data: + rows: + - + - 'Author:' + - Markus Padourek + - + - 'Link:' + - 'chartist-plugin-tooltip' - type: sub-section data: diff --git a/site/examples/example-plugin-tooltip.js b/site/examples/example-plugin-tooltip.js index 5299731d..060cb749 100644 --- a/site/examples/example-plugin-tooltip.js +++ b/site/examples/example-plugin-tooltip.js @@ -11,7 +11,11 @@ var chart = new Chartist.Line('.ct-chart', { {meta: 'other description', value: 4}, {meta: 'other description', value: 2} ] + ] }, { + low: 0, + high: 8, + fullWidth: true, plugins: [ Chartist.plugins.tooltip() ] diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index f0f99d1f..af47a09f 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -71,6 +71,7 @@ + From 1f7e44445922aecf8b7392fae9bd78a18e6bcb68 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 19 Apr 2015 20:14:53 +0200 Subject: [PATCH 213/593] Fixed bug with Chartist.extend when null property is extended --- src/scripts/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index eeffc9e9..8858dfdf 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -47,7 +47,7 @@ var Chartist = { var sources = Array.prototype.slice.call(arguments, 1); sources.forEach(function(source) { for (var prop in source) { - if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) { + if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) { target[prop] = Chartist.extend({}, target[prop], source[prop]); } else { target[prop] = source[prop]; From 85e4e37f4b63a71e471858ccbb582381f89abae8 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 24 Apr 2015 14:23:44 +0200 Subject: [PATCH 214/593] Refactored getDataArray for simplification and fixed type conversion issue with data arrays for pie charts --- src/scripts/core.js | 32 ++++++++--------------- test/spec/spec-core.js | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 8858dfdf..d0fe936a 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -308,10 +308,6 @@ var Chartist = { * @return {Array} A plain array that contains the data to be visualized in the chart */ Chartist.getDataArray = function (data, reverse) { - var array = [], - value, - localData; - // If the data should be reversed but isn't we need to reverse it // If it's reversed but it shouldn't we need to reverse it back // That's required to handle data updates correctly and to reflect the responsive configurations @@ -320,27 +316,21 @@ var Chartist = { data.reversed = !data.reversed; } - for (var i = 0; i < data.series.length; i++) { - // If the series array contains an object with a data property we will use the property - // otherwise the value directly (array or number). - // We create a copy of the original data array with Array.prototype.push.apply - localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; - if(localData instanceof Array) { - array[i] = []; - Array.prototype.push.apply(array[i], localData); + // Rcursively walks through nested arrays and convert string values to numbers and objects with value properties + // to values. Check the tests in data core -> data normalization for a detailed specification of expected values + function recursiveConvert(value) { + if(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) { + return 0; + } else if((value.data || value) instanceof Array) { + return (value.data || value).map(recursiveConvert); + } else if(value.hasOwnProperty('value')) { + return recursiveConvert(value.value); } else { - array[i] = localData; - } - - // Convert object values to numbers - for (var j = 0; j < array[i].length; j++) { - value = array[i][j]; - value = value.value === 0 ? 0 : (value.value || value); - array[i][j] = +value; + return +value; } } - return array; + return data.series.map(recursiveConvert); }; /** diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 4b4ee2f4..ea3871f6 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -122,6 +122,64 @@ describe('Chartist core', function() { ); }); + it('normalize mixed series for pie chart correctly', function() { + var data = { + series: [1, {value: 0}, 3, {value: 4}, 5, 6, 7, 8] + }; + + expect(Chartist.getDataArray(data)).toEqual( + [1, 0, 3, 4, 5, 6, 7, 8] + ); + }); + + it('normalize mixed series with string values for pie chart correctly', function() { + var data = { + series: ['1', {value: '0'}, '3', {value: '4'}, '5', '6', '7', '8'] + }; + + expect(Chartist.getDataArray(data)).toEqual( + [1, 0, 3, 4, 5, 6, 7, 8] + ); + }); + + it('normalize mixed series types with string values correctly', function() { + var data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + {data: ['1', '0', '3', '4', '5', '6']}, + ['1', {value: '0'}, '3', {value: '4'}, '5', '6', '7', '8'], + {data: ['1', '0', {value: '3'}]} + ] + }; + + expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( + [ + [1, 0, 3, 4, 5, 6, 0, 0, 0, 0], + [1, 0, 3, 4, 5, 6, 7, 8, 0, 0], + [1, 0, 3, 0, 0, 0, 0, 0, 0, 0] + ] + ); + }); + + it('normalize mixed series types with weird values correctly', function() { + var data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + {data: [null, NaN, undefined, '4', '5', '6']}, + ['1', {value: null}, '3', {value: NaN}, '5', '6', '7', '8'], + {data: ['1', '0', {value: undefined}]} + ] + }; + + expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( + [ + [0, 0, 0, 4, 5, 6, 0, 0, 0, 0], + [1, 0, 3, 0, 5, 6, 7, 8, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + ); + }); + it('should normalize correctly with 0 values in data series array objects', function() { var data = { labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], From b4ede90dc57db114c08520f630426e4fa2e568cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thilo=20Schmalfu=C3=9F?= Date: Fri, 24 Apr 2015 09:25:08 +0200 Subject: [PATCH 215/593] Workaround: Prevent Firefox from dying with a DOM exception when calling getBBox() on an invisible node. --- src/scripts/svg.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 1a4796f2..4a29652d 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -306,6 +306,24 @@ return this; } + /** + * "Save" way to get property value from svg BoundingBox. + * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node. + * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/) + * + * @memberof Chartist.Svg + * @param {SVGElement} node The svg node to + * @param {String} prop The property to fetch (ex.: height, width, ...) + * @returns {Number} The value of the given bbox property + */ + function getBBoxProperty(node, prop) { + try { + return node.getBBox()[prop]; + } catch(e) {} + + return 0; + } + /** * Get element height with fallback to svg BoundingBox or parent container dimensions: * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) @@ -314,7 +332,7 @@ * @return {Number} The elements height in pixels */ function height() { - return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; + return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight; } /** @@ -325,7 +343,7 @@ * @return {Number} The elements width in pixels */ function width() { - return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth; } /** From fbd98d5ee3c1dac17252367599023a3524834ca4 Mon Sep 17 00:00:00 2001 From: Bastian Gruber Date: Sat, 25 Apr 2015 16:32:20 +0200 Subject: [PATCH 216/593] added new link to an angular directive --- site/data/pages/index.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 4f12c389..5dacbf4f 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -219,6 +219,9 @@ sections: - - 'ng-chartist.js' - Angular Directive + - + - 'chartistAngularDirective.js' + - Angular Directive - - 'react-chartist' - React Component @@ -228,7 +231,7 @@ sections: - - 'tablepress_chartist' - Wordpress / Tablepress Extension - - + - - 'ember-cli-chartist' - Ember Addon - title: Chart CSS animation example From 271fa38180b0db5aa2f21f552d113bbeeedb9da9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 26 Apr 2015 12:24:39 +0200 Subject: [PATCH 217/593] Added missing memberof to some functions in documentation, fixes #291 --- src/scripts/svg.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 4a29652d..fb886b3e 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -108,6 +108,7 @@ /** * Returns the parent Chartist.SVG wrapper object * + * @memberof Chartist.Svg * @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. */ function parent() { @@ -117,6 +118,7 @@ /** * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. * + * @memberof Chartist.Svg * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element */ function root() { @@ -130,6 +132,7 @@ /** * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. * + * @memberof Chartist.Svg * @param {String} selector A CSS selector that is used to query for child SVG elements * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found */ @@ -141,6 +144,7 @@ /** * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. * + * @memberof Chartist.Svg * @param {String} selector A CSS selector that is used to query for child SVG elements * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found */ From 2fe5a1d8cb114362a212e17140dba0f634bc9ff0 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 26 Apr 2015 12:27:50 +0200 Subject: [PATCH 218/593] Added JSF Package to documentation --- site/data/pages/index.yml | 3 +++ src/scripts/core.js | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 5dacbf4f..2a61c4d8 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -234,6 +234,9 @@ sections: - - 'ember-cli-chartist' - Ember Addon + - + - 'ChartistJSF' + - Java Server Faces (Prime Faces) Component - title: Chart CSS animation example level: 3 items: diff --git a/src/scripts/core.js b/src/scripts/core.js index d0fe936a..f4f60ca3 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -570,10 +570,15 @@ var Chartist = { Chartist.createChartRect = function (svg, options, fallbackPadding) { var yOffset = options.axisY ? options.axisY.offset || 0 : 0, xOffset = options.axisX ? options.axisX.offset || 0 : 0, - w = Chartist.stripUnit(options.width) || svg.width(), - h = Chartist.stripUnit(options.height) || svg.height(), + // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 + w = svg.width() || Chartist.stripUnit(options.width) || 0, + h = svg.height() || Chartist.stripUnit(options.height) || 0, normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); + // If settings were to small to cope with offset (legacy) and padding, we'll adjust + w = Math.max(w, xOffset + normalizedPadding.left + normalizedPadding.right); + h = Math.max(h, yOffset + normalizedPadding.top + normalizedPadding.bottom); + return { x1: normalizedPadding.left + yOffset, y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom), From 067a7b168211acf88b46e03f1a01f16d055e0c57 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 26 Apr 2015 17:24:37 +0200 Subject: [PATCH 219/593] Fixed some inconsistent documentation in Pie.js --- src/scripts/charts/pie.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 471c45f6..a1c1ab74 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -19,7 +19,7 @@ height: undefined, // 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} chartPadding: 5, - // Override the class names that get used to generate the SVG structure of the chart + // Override the class names that are used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-pie', series: 'ct-series', @@ -229,7 +229,7 @@ * * @memberof Chartist.Pie * @param {String|Node} query A selector query string or directly a DOM element - * @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 objects that contain a data property with the value and a className property to override the CSS class name for the series group. + * @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. * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] * @return {Object} An object with a version and an update method to manually redraw the chart @@ -270,17 +270,20 @@ * }); * * @example - * // Overriding the class names for individual series + * // Overriding the class names for individual series and include meta data * new Chartist.Pie('.ct-chart', { * series: [{ - * data: 20, - * className: 'my-custom-class-one' + * value: 20, + * className: 'my-custom-class-one', + * meta: 'Meta One' * }, { - * data: 10, - * className: 'my-custom-class-two' + * value: 10, + * className: 'my-custom-class-two', + * meta: 'Meta Two' * }, { - * data: 70, - * className: 'my-custom-class-three' + * value: 70, + * className: 'my-custom-class-three', + * meta: 'Meta Three' * }] * }); */ From fa7c70b56a0d44baa1528fc3500357151ed13613 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 26 Apr 2015 17:27:34 +0200 Subject: [PATCH 220/593] Special condition to check single value should also include object value notation, fixes #265 --- src/scripts/charts/pie.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index a1c1ab74..917cc7b6 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -113,7 +113,7 @@ // Check if there is only one non-zero value in the series array. var hasSingleValInSeries = this.data.series.filter(function(val) { - return val !== 0; + return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; // Draw the series From 3b0c7022d0d778064b5c3487c28abb752db2bb24 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 26 Apr 2015 17:34:57 +0200 Subject: [PATCH 221/593] Fix a bug where meta was only added when series name was specified --- src/scripts/charts/pie.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 917cc7b6..be963924 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -121,13 +121,11 @@ for (var i = 0; i < this.data.series.length; i++) { seriesGroups[i] = this.svg.elem('g', null, null, true); - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) - }, Chartist.xmlNs.uri); - } + // If the series is an object and contains a name or meta data we add a custom attribute + seriesGroups[i].attr({ + 'series-name': this.data.series[i].name, + 'meta': Chartist.serialize(this.data.series[i].meta) + }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ From 62a80d289d2e225eccc54c7bc0c989291019abde Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 26 Apr 2015 17:37:23 +0200 Subject: [PATCH 222/593] Added some more example documentation to Pie --- src/scripts/charts/pie.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index be963924..2ecde065 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -268,18 +268,23 @@ * }); * * @example - * // Overriding the class names for individual series and include meta data + * // Overriding the class names for individual series as well as a name and meta data. + * // The name will be written as ct:series-name attribute and the meta data will be serialized and written + * // to a ct:meta attribute. * new Chartist.Pie('.ct-chart', { * series: [{ * value: 20, + * name: 'Series 1', * className: 'my-custom-class-one', * meta: 'Meta One' * }, { * value: 10, + * name: 'Series 2', * className: 'my-custom-class-two', * meta: 'Meta Two' * }, { * value: 70, + * name: 'Series 3', * className: 'my-custom-class-three', * meta: 'Meta Three' * }] From 91e834d08ade7da2a039545b7aaaacddd7ac75c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thilo=20Schmalfu=C3=9F?= Date: Sun, 26 Apr 2015 14:54:14 +0200 Subject: [PATCH 223/593] Centralized high/low calculations in getHighLow() method and added support for empty charts. --- src/scripts/charts/bar.js | 4 ++-- src/scripts/charts/line.js | 5 +---- src/scripts/core.js | 45 ++++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 9b03259b..4e0ee026 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -100,9 +100,9 @@ return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); }); - highLow = Chartist.getHighLow([serialSums]); + highLow = Chartist.getHighLow([serialSums], options); } else { - highLow = Chartist.getHighLow(normalizedData); + highLow = Chartist.getHighLow(normalizedData, options); } // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index eb166eee..5c680c96 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -103,10 +103,7 @@ var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); - var highLow = Chartist.getHighLow(normalizedData); - // Overrides of high / low from settings - highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); - highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); + var highLow = Chartist.getHighLow(normalizedData, options); var axisX = new Chartist.StepAxis( Chartist.Axis.units.x, diff --git a/src/scripts/core.js b/src/scripts/core.js index 8858dfdf..5bd6daa8 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -435,28 +435,46 @@ var Chartist = { * * @memberof Chartist.Core * @param {Array} dataArray The array that contains the data to be visualized in the chart + * @param {Object} options The Object that contains all the optional values for the chart * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ - Chartist.getHighLow = function (dataArray) { + Chartist.getHighLow = function (dataArray, options) { var i, j, highLow = { - high: -Number.MAX_VALUE, - low: Number.MAX_VALUE - }; + high: options.high === undefined ? -Number.MAX_VALUE : +options.high, + low: options.low === undefined ? Number.MAX_VALUE : +options.low + }, + findHigh = options.high === undefined, + findLow = options.low === undefined; for (i = 0; i < dataArray.length; i++) { for (j = 0; j < dataArray[i].length; j++) { - if (dataArray[i][j] > highLow.high) { + if (findHigh && dataArray[i][j] > highLow.high) { highLow.high = dataArray[i][j]; } - if (dataArray[i][j] < highLow.low) { + if (findLow && dataArray[i][j] < highLow.low) { highLow.low = dataArray[i][j]; } } } + // If high and low are the same because of misconfiguration or flat data (only the same value) we need + // to set the high or low to 0 depending on the polarity + if (highLow.high <= highLow.low) { + // If both values are 0 we set high to 1 + if (highLow.low === 0) { + highLow.high = 1; + } else if (highLow.low < 0) { + // If we have the same negative value for the bounds we set bounds.high to 0 + highLow.high = 0; + } else { + // If we have the same positive value for the bounds we set bounds.low to 0 + highLow.low = 0; + } + } + return highLow; }; @@ -479,21 +497,6 @@ var Chartist = { low: highLow.low }; - // If high and low are the same because of misconfiguration or flat data (only the same value) we need - // to set the high or low to 0 depending on the polarity - if(bounds.high === bounds.low) { - // If both values are 0 we set high to 1 - if(bounds.low === 0) { - bounds.high = 1; - } else if(bounds.low < 0) { - // If we have the same negative value for the bounds we set bounds.high to 0 - bounds.high = 0; - } else { - // If we have the same positive value for the bounds we set bounds.low to 0 - bounds.low = 0; - } - } - // Overrides of high / low based on reference value, it will make sure that the invisible reference value is // used to generate the chart. This is useful when the chart always needs to contain the position of the // invisible reference value in the view i.e. for bipolar scales. From a240fad16e590256b90830874cb722a0e08f9962 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 7 May 2015 13:40:57 +0200 Subject: [PATCH 224/593] Fixed bug with pie chart meta data not rendered on slice, fixes #272 --- src/scripts/charts/pie.js | 6 +++--- test/spec/spec-pie-chart.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 test/spec/spec-pie-chart.js diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 2ecde065..f7ab50fb 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -123,8 +123,7 @@ // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) + 'series-name': this.data.series[i].name }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one @@ -161,7 +160,8 @@ // Adding the pie series value to the path pathElement.attr({ - 'value': dataArray[i] + 'value': dataArray[i], + 'meta': Chartist.serialize(this.data.series[i].meta) }, Chartist.xmlNs.uri); // If this is a donut, we add the stroke-width as style attribute diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js new file mode 100644 index 00000000..db8a1932 --- /dev/null +++ b/test/spec/spec-pie-chart.js @@ -0,0 +1,36 @@ +describe('Pie chart tests', function() { + 'use strict'; + + beforeEach(function() { + + }); + + afterEach(function() { + + }); + + describe('Meta data tests', function() { + it('should render meta data correctly on slice with mixed value array', function (done) { + jasmine.getFixtures().set('
    '); + + var meta = { + test: 'Serialized Test' + }; + + var data = { + labels: ['A', 'B', 'C'], + series: [5, { + value: 8, + meta: meta + }, 1] + }; + + var chart = new Chartist.Pie('.ct-chart', data); + + chart.on('created', function() { + expect(Chartist.deserialize($('.ct-slice').eq(1).attr('ct:meta'))).toEqual(meta); + done(); + }); + }); + }); +}); From 50e9724bb89fb81f3fe3ec71a9997f95263f47fe Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 7 May 2015 13:53:44 +0200 Subject: [PATCH 225/593] Removed restriction to SVGElements so Chartist.Svg can be used for HTML DOM elements, fixes 261 --- src/scripts/svg.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index fb886b3e..03c48443 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -22,7 +22,7 @@ * * @memberof Chartist.Svg * @constructor - * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg + * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg * @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. * @param {String} className This class or class list will be added to the SVG element * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child @@ -30,7 +30,7 @@ */ function Svg(name, attributes, className, parent, insertFirst) { // If Svg is getting called with an SVG element we just return the wrapper - if(name instanceof SVGElement) { + if(name instanceof Element) { this._node = name; } else { this._node = document.createElementNS(svgNs, name); From 2a6f90e6479b371536bba6a81706cbe3c462bc93 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 7 May 2015 18:07:10 +0200 Subject: [PATCH 226/593] Changed line chart behavior to draw points from interpolated values and added step interpolation, fixes #295 --- src/scripts/charts/line.js | 151 +++++++++++++++++++---------------- src/scripts/interpolation.js | 73 ++++++++++++++--- src/scripts/svg-path.js | 28 ++++--- 3 files changed, 160 insertions(+), 92 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 5c680c96..4141841f 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -181,99 +181,108 @@ (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - var pathCoordinates = []; + var pathCoordinates = [], + pathData = []; normalizedData[seriesIndex].forEach(function(value, valueIndex) { var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos }; pathCoordinates.push(p.x, p.y); + pathData.push({ + value: value, + valueIndex: valueIndex, + meta: Chartist.getMetaData(series, valueIndex) + }); + }.bind(this)); + + var smoothing = typeof options.lineSmooth === 'function' ? + options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()); + // Interpolating path where pathData will be used to annotate each path element so we can trace back the original + // index, value and meta data + var path = smoothing(pathCoordinates, pathData); - //If we should show points we need to create them now to avoid secondary loop - // Small offset for Firefox to render squares correctly - if (options.showPoint) { + // If we should show points we need to create them now to avoid secondary loop + // Points are drawn from the pathElements returned by the interpolation function + // Small offset for Firefox to render squares correctly + if (options.showPoint) { + + path.pathElements.forEach(function(pathElement) { var point = seriesGroups[seriesIndex].elem('line', { - x1: p.x, - y1: p.y, - x2: p.x + 0.01, - y2: p.y + x1: pathElement.x, + y1: pathElement.y, + x2: pathElement.x + 0.01, + y2: pathElement.y }, options.classNames.point).attr({ - 'value': value, - 'meta': Chartist.getMetaData(series, valueIndex) + 'value': pathElement.data.value, + 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'point', - value: value, - index: valueIndex, + value: pathElement.data.value, + index: pathElement.data.valueIndex, group: seriesGroups[seriesIndex], element: point, - x: p.x, - y: p.y + x: pathElement.x, + y: pathElement.y }); - } - }.bind(this)); - - // TODO: Nicer handling of conditions, maybe composition? - if (options.showLine || options.showArea) { - var smoothing = typeof options.lineSmooth === 'function' ? - options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()), - path = smoothing(pathCoordinates); + }.bind(this)); + } - if(options.showLine) { - var line = seriesGroups[seriesIndex].elem('path', { - d: path.stringify() - }, options.classNames.line, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); + if(options.showLine) { + var line = seriesGroups[seriesIndex].elem('path', { + d: path.stringify() + }, options.classNames.line, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[seriesIndex], - path: path.clone(), - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: line - }); - } + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[seriesIndex], + path: path.clone(), + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], + element: line + }); + } - if(options.showArea) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); + if(options.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); - // We project the areaBase value into screen coordinates - var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; + // We project the areaBase value into screen coordinates + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; - // Clone original path and splice our new area path to add the missing path elements to close the area shape - var areaPath = path.clone(); - // Modify line path and add missing elements for area - areaPath.position(0) - .remove(1) - .move(chartRect.x1, areaBaseProjected) - .line(pathCoordinates[0], pathCoordinates[1]) - .position(areaPath.pathElements.length) - .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); + // Clone original path and splice our new area path to add the missing path elements to close the area shape + var areaPath = path.clone(); + // Modify line path and add missing elements for area + areaPath.position(0) + .remove(1) + .move(chartRect.x1, areaBaseProjected) + .line(pathCoordinates[0], pathCoordinates[1]) + .position(areaPath.pathElements.length) + .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); - // Create the new path for the area shape with the area class from the options - var area = seriesGroups[seriesIndex].elem('path', { - d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); + // Create the new path for the area shape with the area class from the options + var area = seriesGroups[seriesIndex].elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); - this.eventEmitter.emit('draw', { - type: 'area', - values: normalizedData[seriesIndex], - path: areaPath.clone(), - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: area - }); - } + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[seriesIndex], + path: areaPath.clone(), + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], + element: area + }); } }.bind(this)); diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index ab0e45d8..97dc3a1f 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -16,11 +16,11 @@ * @return {Function} */ Chartist.Interpolation.none = function() { - return function cardinal(pathCoordinates) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + return function none(pathCoordinates, valueData) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); for(var i = 3; i < pathCoordinates.length; i += 2) { - path.line(pathCoordinates[i - 1], pathCoordinates[i]); + path.line(pathCoordinates[i - 1], pathCoordinates[i], false, valueData[(i - 1) / 2]); } return path; @@ -57,8 +57,8 @@ var d = 1 / Math.max(1, options.divisor); - return function simple(pathCoordinates) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + return function simple(pathCoordinates, valueData) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); for(var i = 2; i < pathCoordinates.length; i += 2) { var prevX = pathCoordinates[i - 2], @@ -73,7 +73,9 @@ currX - length, currY, currX, - currY + currY, + false, + valueData[i / 2] ); } @@ -112,13 +114,13 @@ var t = Math.min(1, Math.max(0, options.tension)), c = 1 - t; - return function cardinal(pathCoordinates) { + return function cardinal(pathCoordinates, valueData) { // If less than two points we need to fallback to no smoothing if(pathCoordinates.length <= 4) { - return Chartist.Interpolation.none()(pathCoordinates); + return Chartist.Interpolation.none()(pathCoordinates, valueData); } - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]), + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), z; for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { @@ -151,7 +153,9 @@ (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), p[2].x, - p[2].y + p[2].y, + false, + valueData[(i + 2) / 2] ); } @@ -159,4 +163,53 @@ }; }; + /** + * 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. + * + * 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`. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.step({ + * postpone: true + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param options + * @returns {Function} + */ + Chartist.Interpolation.step = function(options) { + var defaultOptions = { + postpone: true + }; + + options = Chartist.extend({}, defaultOptions, options); + + return function step(pathCoordinates, valueData) { + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); + + for (var i = 2; i < pathCoordinates.length; i += 2) { + var prevX = pathCoordinates[i - 2], + prevY = pathCoordinates[i - 1], + currX = pathCoordinates[i], + currY = pathCoordinates[i + 1]; + + if(options.postpone) { + path.line(currX, prevY, false, valueData[(i - 2) / 2]); + } else { + path.line(prevX, currY, false, valueData[i / 2]); + } + + + path.line(currX, currY, false, valueData[i / 2]); + } + + return path; + }; + }; + }(window, document, Chartist)); diff --git a/src/scripts/svg-path.js b/src/scripts/svg-path.js index f0f0e6d3..de0c2464 100644 --- a/src/scripts/svg-path.js +++ b/src/scripts/svg-path.js @@ -31,10 +31,12 @@ accuracy: 3 }; - function element(command, params, pathElements, pos, relative) { - pathElements.splice(pos, 0, Chartist.extend({ + function element(command, params, pathElements, pos, relative, data) { + var pathElement = Chartist.extend({ command: relative ? command.toLowerCase() : command.toUpperCase() - }, params)); + }, params, data ? { data: data } : {} ); + + pathElements.splice(pos, 0, pathElement); } function forEachParam(pathElements, cb) { @@ -95,13 +97,14 @@ * @param {Number} x The x coordinate for the move element. * @param {Number} y The y coordinate for the move element. * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function move(x, y, relative) { + function move(x, y, relative, data) { element('M', { x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } @@ -112,13 +115,14 @@ * @param {Number} x The x coordinate for the line element. * @param {Number} y The y coordinate for the line element. * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function line(x, y, relative) { + function line(x, y, relative, data) { element('L', { x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } @@ -133,9 +137,10 @@ * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function curve(x1, y1, x2, y2, x, y, relative) { + function curve(x1, y1, x2, y2, x, y, relative, data) { element('C', { x1: +x1, y1: +y1, @@ -143,7 +148,7 @@ y2: +y2, x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } @@ -159,9 +164,10 @@ * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function arc(rx, ry, xAr, lAf, sf, x, y, relative) { + function arc(rx, ry, xAr, lAf, sf, x, y, relative, data) { element('A', { rx: +rx, ry: +ry, @@ -170,7 +176,7 @@ sf: +sf, x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } From 34d303d576725677dbf985d832d532b074461b2b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 7 May 2015 18:21:34 +0200 Subject: [PATCH 227/593] Switched from object literal accessor definition to regular function, fixes #278 --- src/scripts/base.js | 4 ++-- src/scripts/core.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index 7afb5bd8..375079e7 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -44,7 +44,7 @@ // Only re-created the chart if it has been initialized yet if(!this.initializeTimeoutId) { - this.createChart(this.optionsProvider.currentOptions); + this.createChart(this.optionsProvider.getCurrentOptions()); } // Return a reference to the chart object to chain up calls @@ -117,7 +117,7 @@ }); // Create the first chart - this.createChart(this.optionsProvider.currentOptions); + this.createChart(this.optionsProvider.getCurrentOptions()); // As chart is initialized from the event loop now we can reset our timeout reference // This is important if the chart gets initialized on the same element twice diff --git a/src/scripts/core.js b/src/scripts/core.js index f8044bbf..9343bf92 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -768,10 +768,10 @@ var Chartist = { updateCurrentOptions(true); return { - get currentOptions() { + removeMediaQueryListeners: removeMediaQueryListeners, + getCurrentOptions: function getCurrentOptions() { return Chartist.extend({}, currentOptions); - }, - removeMediaQueryListeners: removeMediaQueryListeners + } }; }; From 6e8a84e6c541a617d8afe919fcfaef30dacd6e45 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 7 May 2015 18:32:28 +0200 Subject: [PATCH 228/593] Fixed tests for 34d303d --- test/spec/spec-base-chart.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/spec/spec-base-chart.js b/test/spec/spec-base-chart.js index bf36a139..8bc4fbec 100644 --- a/test/spec/spec-base-chart.js +++ b/test/spec/spec-base-chart.js @@ -166,8 +166,8 @@ describe('Base chart tests', function() { expect(optionsChangedEventsSpy.calls.count()).toBe(0); // Updated options should be present as we updated it in same call stack before chart creation - expect(chart.optionsProvider.currentOptions.showArea).toBe(false); - expect(chart.optionsProvider.currentOptions.showPoint).toBe(true); + expect(chart.optionsProvider.getCurrentOptions().showArea).toBe(false); + expect(chart.optionsProvider.getCurrentOptions().showPoint).toBe(true); done(); }); }); @@ -239,8 +239,8 @@ describe('Base chart tests', function() { chart.on('created', function() { // showArea is false in the default settings and as we didn't use current options and override option it should // be back to default. - expect(chart.optionsProvider.currentOptions.showArea).toBe(false); - expect(chart.optionsProvider.currentOptions.showPoint).toBe(false); + expect(chart.optionsProvider.getCurrentOptions().showArea).toBe(false); + expect(chart.optionsProvider.getCurrentOptions().showPoint).toBe(false); done(); }); }); @@ -263,8 +263,8 @@ describe('Base chart tests', function() { chart.update(null, updatedOptions, true); chart.on('created', function() { - expect(chart.optionsProvider.currentOptions.showArea).toBe(true); - expect(chart.optionsProvider.currentOptions.showPoint).toBe(false); + expect(chart.optionsProvider.getCurrentOptions().showArea).toBe(true); + expect(chart.optionsProvider.getCurrentOptions().showPoint).toBe(false); done(); }); }); From aafb4e87897e694c2ce79a50b62994a15c98bf2d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 8 May 2015 10:19:40 +0200 Subject: [PATCH 229/593] Added functionality to handle holes in line charts, fixes parts of #294 --- src/scripts/core.js | 2 +- src/scripts/interpolation.js | 242 +++++++++++++++++++++++++---------- src/scripts/svg-path.js | 22 ++++ test/spec/spec-core.js | 6 +- test/spec/spec-line-chart.js | 192 +++++++++++++++++++++++++-- 5 files changed, 379 insertions(+), 85 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 9343bf92..dc362c68 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -320,7 +320,7 @@ var Chartist = { // to values. Check the tests in data core -> data normalization for a detailed specification of expected values function recursiveConvert(value) { if(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) { - return 0; + return undefined; } else if((value.data || value) instanceof Array) { return (value.data || value).map(recursiveConvert); } else if(value.hasOwnProperty('value')) { diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 97dc3a1f..36012edb 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -17,10 +17,26 @@ */ Chartist.Interpolation.none = function() { return function none(pathCoordinates, valueData) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); + var path = new Chartist.Svg.Path(); + // We need to assume that the first value is a "hole" + var hole = true; - for(var i = 3; i < pathCoordinates.length; i += 2) { - path.line(pathCoordinates[i - 1], pathCoordinates[i], false, valueData[(i - 1) / 2]); + for(var i = 1; i < pathCoordinates.length; i += 2) { + var data = valueData[(i - 1) / 2]; + + // If the current value is undefined we should treat it as a hole start + if(data.value === undefined) { + hole = true; + } else { + // If this value is valid we need to check if we're coming out of a hole + if(hole) { + // If we are coming out of a hole we should first make a move and also reset the hole flag + path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data); + hole = false; + } else { + path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data); + } + } } return path; @@ -58,25 +74,41 @@ var d = 1 / Math.max(1, options.divisor); return function simple(pathCoordinates, valueData) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); + var path = new Chartist.Svg.Path(); + var hole = true; for(var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2], - prevY = pathCoordinates[i - 1], - currX = pathCoordinates[i], - currY = pathCoordinates[i + 1], - length = (currX - prevX) * d; - - path.curve( - prevX + length, - prevY, - currX - length, - currY, - currX, - currY, - false, - valueData[i / 2] - ); + var prevX = pathCoordinates[i - 2]; + var prevY = pathCoordinates[i - 1]; + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var length = (currX - prevX) * d; + var prevData = valueData[(i / 2) - 1]; + var currData = valueData[i / 2]; + + if(prevData.value === undefined) { + hole = true; + } else { + + if(hole) { + path.move(prevX, prevY, false, prevData); + } + + if(currData.value !== undefined) { + path.curve( + prevX + length, + prevY, + currX - length, + currY, + currX, + currY, + false, + currData + ); + + hole = false; + } + } } return path; @@ -114,52 +146,101 @@ var t = Math.min(1, Math.max(0, options.tension)), c = 1 - t; - return function cardinal(pathCoordinates, valueData) { - // If less than two points we need to fallback to no smoothing - if(pathCoordinates.length <= 4) { - return Chartist.Interpolation.none()(pathCoordinates, valueData); - } + // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates + // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards. + // This functionality is necessary to treat "holes" in the line charts + function splitIntoSegments(pathCoordinates, valueData) { + var segments = []; + var hole = true; - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), - z; - - for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { - var p = [ - {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, - {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, - {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, - {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} - ]; - if (z) { - if (!i) { - p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; - } else if (iLen - 4 === i) { - p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; - } else if (iLen - 2 === i) { - p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; - p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; - } + for(var i = 0; i < pathCoordinates.length; i += 2) { + // If this value is a "hole" we set the hole flag + if(valueData[i / 2].value === undefined) { + hole = true; } else { - if (iLen - 4 === i) { - p[3] = p[2]; - } else if (!i) { - p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; + // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment + if(hole) { + segments.push({ + pathCoordinates: [], + valueData: [] + }); + // As we have a valid value now, we are not in a "hole" anymore + hole = false; } - } - path.curve( - (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), - (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), - (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), - (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), - p[2].x, - p[2].y, - false, - valueData[(i + 2) / 2] - ); + // Add to the segment pathCoordinates and valueData + segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); + segments[segments.length - 1].valueData.push(valueData[i / 2]); + } } - return path; + return segments; + } + + return function cardinal(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = splitIntoSegments(pathCoordinates, valueData); + + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + if(segments.length > 1) { + var paths = []; + // For each segment we will recurse the cardinal function + segments.forEach(function(segment) { + paths.push(cardinal(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return Chartist.Svg.Path.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData directly + + // If less than two points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return Chartist.Interpolation.none()(pathCoordinates, valueData); + } + + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), + z; + + for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, + {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, + {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, + {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; + } else if (iLen - 4 === i) { + p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + } else if (iLen - 2 === i) { + p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; + } + } + + path.curve( + (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), + (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), + (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), + (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), + p[2].x, + p[2].y, + false, + valueData[(i + 2) / 2] + ); + } + + return path; + } }; }; @@ -190,22 +271,41 @@ options = Chartist.extend({}, defaultOptions, options); return function step(pathCoordinates, valueData) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); + var path = new Chartist.Svg.Path(); + var hole = true; for (var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2], - prevY = pathCoordinates[i - 1], - currX = pathCoordinates[i], - currY = pathCoordinates[i + 1]; + var prevX = pathCoordinates[i - 2]; + var prevY = pathCoordinates[i - 1]; + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var prevData = valueData[(i / 2) - 1]; + var currData = valueData[i / 2]; - if(options.postpone) { - path.line(currX, prevY, false, valueData[(i - 2) / 2]); + // If last point is a "hole" + if(prevData.value === undefined) { + hole = true; } else { - path.line(prevX, currY, false, valueData[i / 2]); - } - + // If last point is not a "hole" but we just came back out of a "hole" we need to move first + if(hole) { + path.move(prevX, prevY, false, prevData); + } - path.line(currX, currY, false, valueData[i / 2]); + // If the current point is also not a hole we can draw the step lines + if(currData.value !== undefined) { + if(options.postpone) { + // If postponed we should draw the step line with the value of the previous value + path.line(currX, prevY, false, prevData); + } else { + // If not postponed we should draw the step line with the value of the current value + path.line(prevX, currY, false, currData); + } + // Line to the actual point (this should only be a Y-Axis movement + path.line(currX, currY, false, currData); + // Reset the "hole" flag as previous and current point have valid values + hole = false; + } + } } return path; diff --git a/src/scripts/svg-path.js b/src/scripts/svg-path.js index de0c2464..366256b8 100644 --- a/src/scripts/svg-path.js +++ b/src/scripts/svg-path.js @@ -318,6 +318,27 @@ return c; } + /** + * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths. + * + * @memberof Chartist.Svg.Path + * @param {Array} paths A list of paths to be joined together. The order is important. + * @param {boolean} close If the newly created path should be a closed path + * @param {Object} options Path options for the newly created path. + * @return {Chartist.Svg.Path} + */ + + function join(paths, close, options) { + var joinedPath = new Chartist.Svg.Path(close, options); + for(var i = 0; i < paths.length; i++) { + var path = paths[i]; + for(var j = 0; j < path.pathElements.length; j++) { + joinedPath.pathElements.push(path.pathElements[j]); + } + } + return joinedPath; + } + Chartist.Svg.Path = Chartist.Class.extend({ constructor: SvgPath, position: position, @@ -335,4 +356,5 @@ }); Chartist.Svg.Path.elementDescriptions = elementDescriptions; + Chartist.Svg.Path.join = join; }(window, document, Chartist)); diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index ea3871f6..eb503763 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -173,9 +173,9 @@ describe('Chartist core', function() { expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( [ - [0, 0, 0, 4, 5, 6, 0, 0, 0, 0], - [1, 0, 3, 0, 5, 6, 7, 8, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [undefined, undefined, undefined, 4, 5, 6, 0, 0, 0, 0], + [1, undefined, 3, undefined, 5, 6, 7, 8, 0, 0], + [1, 0, undefined, 0, 0, 0, 0, 0, 0, 0] ] ); }); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index ea71a321..737eccb8 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -1,16 +1,16 @@ -describe('Line chart tests', function() { +describe('Line chart tests', function () { 'use strict'; - beforeEach(function() { + beforeEach(function () { }); - afterEach(function() { + afterEach(function () { }); describe('Meta data tests', function () { - it('should render meta data correctly with mixed value array', function(done) { + it('should render meta data correctly with mixed value array', function (done) { jasmine.getFixtures().set('
    '); var meta = { @@ -29,13 +29,13 @@ describe('Line chart tests', function() { var chart = new Chartist.Line('.ct-chart', data); - chart.on('created', function() { + chart.on('created', function () { expect(Chartist.deserialize($('.ct-point').eq(3).attr('ct:meta'))).toEqual(meta); done(); }); }); - it('should render meta data correctly with mixed value array and different normalized data length', function(done) { + it('should render meta data correctly with mixed value array and different normalized data length', function (done) { jasmine.getFixtures().set('
    '); var meta = { @@ -54,13 +54,13 @@ describe('Line chart tests', function() { var chart = new Chartist.Line('.ct-chart', data); - chart.on('created', function() { + chart.on('created', function () { expect(Chartist.deserialize($('.ct-point').eq(3).attr('ct:meta'))).toEqual(meta); done(); }); }); - it('should render meta data correctly with mixed value array and mixed series notation', function(done) { + it('should render meta data correctly with mixed value array and mixed series notation', function (done) { jasmine.getFixtures().set('
    '); var seriesMeta = 9999, @@ -87,12 +87,184 @@ describe('Line chart tests', function() { var chart = new Chartist.Line('.ct-chart', data); - chart.on('created', function() { + chart.on('created', function () { expect(Chartist.deserialize($('.ct-series-a .ct-point').eq(3).attr('ct:meta'))).toEqual(valueMeta); - expect(Chartist.deserialize($('.ct-series-b')).attr('ct:meta')).toEqual(''+seriesMeta); + expect(Chartist.deserialize($('.ct-series-b')).attr('ct:meta')).toEqual('' + seriesMeta); expect(Chartist.deserialize($('.ct-series-b .ct-point').eq(2).attr('ct:meta'))).toEqual(valueMeta); done(); }); }); }); + + describe('Line charts with holes', function () { + it('should render correctly with Interpolation.none and holes everywhere', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }, { + lineSmooth: false + }); + + chart.on('draw', function (context) { + if (context.type === 'line') { + expect(context.path.pathElements.map(function (pathElement) { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with Interpolation.cardinal and holes everywhere', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }, { + lineSmooth: true + }); + + chart.on('draw', function (context) { + if (context.type === 'line') { + expect(context.path.pathElements.map(function (pathElement) { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, + // Cardinal should create Line path segment if only one connection + {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, + // Cardinal should create Curve path segment for 2 or more connections + {command: 'C', data: {valueIndex: 5, value: 3, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: 4, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with Interpolation.simple and holes everywhere', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }, { + lineSmooth: Chartist.Interpolation.simple() + }); + + chart.on('draw', function (context) { + if (context.type === 'line') { + expect(context.path.pathElements.map(function (pathElement) { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, + {command: 'C', data: {valueIndex: 2, value: 0, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, + {command: 'C', data: {valueIndex: 5, value: 3, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: 4, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with postponed Interpolation.step and holes everywhere', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }, { + lineSmooth: Chartist.Interpolation.step() + }); + + chart.on('draw', function (context) { + if (context.type === 'line') { + expect(context.path.pathElements.map(function (pathElement) { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, + {command: 'L', data: {valueIndex: 1, value: 15, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, + {command: 'L', data: {valueIndex: 4, value: 2, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with preponed Interpolation.step and holes everywhere', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }, { + lineSmooth: Chartist.Interpolation.step({ + postpone: false + }) + }); + + chart.on('draw', function (context) { + if (context.type === 'line') { + expect(context.path.pathElements.map(function (pathElement) { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + ]); + done(); + } + }); + }); + }); }); From 0258a584567692b6967501f9337791f8e02e4494 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 8 May 2015 10:45:25 +0200 Subject: [PATCH 230/593] Normalization should not fill with 0 but with undefined now that we support holes in line charts, fixes #294 --- src/scripts/core.js | 2 +- src/scripts/interpolation.js | 5 ++++- test/spec/spec-core.js | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index dc362c68..0033e7f1 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -372,7 +372,7 @@ var Chartist = { } for (var j = dataArray[i].length; j < length; j++) { - dataArray[i][j] = 0; + dataArray[i][j] = undefined; } } diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 36012edb..f5127f0c 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -193,7 +193,10 @@ // Join the segment path data into a single path and return return Chartist.Svg.Path.join(paths); } else { - // If there was only one segment we can proceed regularly by using pathCoordinates and valueData directly + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; // If less than two points we need to fallback to no smoothing if(pathCoordinates.length <= 4) { diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index eb503763..f5170d72 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -96,9 +96,9 @@ describe('Chartist core', function() { expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( [ - [1, 2, 3, 4, 5, 6, 0, 0, 0, 0], - [1, 2, 3, 4, 5, 6, 7, 8, 0, 0], - [1, 2, 3, 0, 0, 0, 0, 0, 0, 0] + [1, 2, 3, 4, 5, 6, undefined, undefined, undefined, undefined], + [1, 2, 3, 4, 5, 6, 7, 8, undefined, undefined], + [1, 2, 3, undefined, undefined, undefined, undefined, undefined, undefined, undefined] ] ); }); @@ -115,9 +115,9 @@ describe('Chartist core', function() { expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( [ - [1, 0, 3, 4, 5, 6, 0, 0, 0, 0], - [1, 0, 3, 4, 5, 6, 7, 8, 0, 0], - [1, 0, 3, 0, 0, 0, 0, 0, 0, 0] + [1, 0, 3, 4, 5, 6, undefined, undefined, undefined, undefined], + [1, 0, 3, 4, 5, 6, 7, 8, undefined, undefined], + [1, 0, 3, undefined, undefined, undefined, undefined, undefined, undefined, undefined] ] ); }); @@ -154,9 +154,9 @@ describe('Chartist core', function() { expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( [ - [1, 0, 3, 4, 5, 6, 0, 0, 0, 0], - [1, 0, 3, 4, 5, 6, 7, 8, 0, 0], - [1, 0, 3, 0, 0, 0, 0, 0, 0, 0] + [1, 0, 3, 4, 5, 6, undefined, undefined, undefined, undefined], + [1, 0, 3, 4, 5, 6, 7, 8, undefined, undefined], + [1, 0, 3, undefined, undefined, undefined, undefined, undefined, undefined, undefined] ] ); }); @@ -173,9 +173,9 @@ describe('Chartist core', function() { expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( [ - [undefined, undefined, undefined, 4, 5, 6, 0, 0, 0, 0], - [1, undefined, 3, undefined, 5, 6, 7, 8, 0, 0], - [1, 0, undefined, 0, 0, 0, 0, 0, 0, 0] + [undefined, undefined, undefined, 4, 5, 6, undefined, undefined, undefined, undefined], + [1, undefined, 3, undefined, 5, 6, 7, 8, undefined, undefined], + [1, 0, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined] ] ); }); From 485ae62c57a2c9a229e6780764584e3b2b8da0ac Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 8 May 2015 11:08:50 +0200 Subject: [PATCH 231/593] Added series data and meta information to events, fixes #293 --- src/scripts/charts/bar.js | 3 +++ src/scripts/charts/line.js | 7 +++++++ src/scripts/charts/pie.js | 9 ++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 4e0ee026..3df3b4fb 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -270,6 +270,9 @@ type: 'bar', value: value, index: valueIndex, + meta: Chartist.getMetaData(series, valueIndex), + series: series, + seriesIndex: seriesIndex, chartRect: chartRect, group: seriesGroups[seriesIndex], element: bar diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 4141841f..162fee66 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -223,6 +223,9 @@ type: 'point', value: pathElement.data.value, index: pathElement.data.valueIndex, + meta: pathElement.data.meta, + series: series, + seriesIndex: seriesIndex, group: seriesGroups[seriesIndex], element: point, x: pathElement.x, @@ -244,6 +247,8 @@ path: path.clone(), chartRect: chartRect, index: seriesIndex, + series: series, + seriesIndex: seriesIndex, group: seriesGroups[seriesIndex], element: line }); @@ -278,6 +283,8 @@ type: 'area', values: normalizedData[seriesIndex], path: areaPath.clone(), + series: series, + seriesIndex: seriesIndex, chartRect: chartRect, index: seriesIndex, group: seriesGroups[seriesIndex], diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index f7ab50fb..8c638570 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -119,17 +119,18 @@ // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { + var series = this.data.series[i]; seriesGroups[i] = this.svg.elem('g', null, null, true); // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[i].attr({ - 'series-name': this.data.series[i].name + 'series-name': series.name }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) ].join(' ')); var endAngle = startAngle + dataArray[i] / totalDataSum * 360; @@ -161,7 +162,7 @@ // Adding the pie series value to the path pathElement.attr({ 'value': dataArray[i], - 'meta': Chartist.serialize(this.data.series[i].meta) + 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // If this is a donut, we add the stroke-width as style attribute @@ -177,6 +178,8 @@ value: dataArray[i], totalDataSum: totalDataSum, index: i, + meta: series.meta, + series: series, group: seriesGroups[i], element: pathElement, path: path.clone(), From 8bea1acc4a554f762e562604d99a2855c172b392 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 8 May 2015 11:45:45 +0200 Subject: [PATCH 232/593] Added default styles for bar and horizontal bar labels that make more sense, fixes #303 --- src/scripts/charts/bar.js | 8 +++++++- src/styles/chartist.scss | 14 ++++++++++++++ src/styles/settings/_chartist-settings.scss | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 3df3b4fb..d7b00ec0 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -70,6 +70,7 @@ // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', + horizontalBars: 'ct-horizontal-bars', label: 'ct-label', labelGroup: 'ct-labels', series: 'ct-series', @@ -92,7 +93,12 @@ highLow; // Create new svg element - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + this.svg = Chartist.createSvg( + this.container, + options.width, + options.height, + options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '') + ); if(options.stackBars) { // If stacked bars we need to calculate the high low from stacked values from each series diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index 2456997b..75219208 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -99,6 +99,20 @@ @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align); } + .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal} { + text-align: center; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal} { + text-align: left; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical} { + display: flex; + align-items: center; + justify-content: flex-end; + } + .#{$ct-class-grid} { @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); } diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss index b244b592..bca20d7d 100644 --- a/src/styles/settings/_chartist-settings.scss +++ b/src/styles/settings/_chartist-settings.scss @@ -6,6 +6,7 @@ $ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, $ct-class-chart: ct-chart !default; $ct-class-chart-line: ct-chart-line !default; $ct-class-chart-bar: ct-chart-bar !default; +$ct-class-horizontal-bars: ct-horizontal-bars !default; $ct-class-chart-pie: ct-chart-pie !default; $ct-class-label: ct-label !default; $ct-class-series: ct-series !default; From b8afa5caf49908bea4de0175b55657f7ffde1729 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 8 May 2015 20:54:20 +0200 Subject: [PATCH 233/593] documentation: Added base64 data URI for chartist icon in sticky nav --- site/styles/main.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/styles/main.scss b/site/styles/main.scss index dea50f46..20fdcc0b 100644 --- a/site/styles/main.scss +++ b/site/styles/main.scss @@ -121,7 +121,7 @@ code { border-radius: 50%; border: 2px solid #F4C63D; background-size: 32px 32px; - background: #F4C63D url("http://github.com/images/chartist-icon.svg") no-repeat center; + background: #F4C63D url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMzIgMzIiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnIGlkPSJoZWFkIj48cGF0aCBmaWxsPSIjNzU1NDNCIiBkPSJNMTMuOCAyMC42czEuNiA1LTMuOSA1bDQuOSAxLjUgNC00LjItNS0yLjN6Ii8+PHBhdGggZmlsbD0iI0IyNDk0OSIgZD0iTTE3LjEgMjVzLTQuMS0xLjUtNS45IDEuMWwzLjcuOSAyLjItMnoiLz48cGF0aCBmaWxsPSIjRDM5Qzc2IiBkPSJNOS45IDI1LjRjMi4xIDEuMSA1IC42IDYgMCAxLjUtLjggMS41LTMgMS4xLTMuMi0uMi0uMS0yLjIgMS4zLTUuOS4xbC40LTMuMy01LjktLjJMOS43IDguNHM3LTIuOSAxNCAwVjE5Yy40LS4xLjgtLjIgMS4xIDAgLjkuMyAxLjEgMS40LjYgMi41LS40LjctMSAxLjMtMS43IDEuNHY2LjJzLTcuMiA0LjgtMTUuMSAyLjFjMCAwLTIuNS0uOC0yLjMtMy40IDAtLjItLjItMS45IDMuNi0yLjR6Ii8+PGcgZmlsbD0iIzYzNDEyOCI+PHBhdGggZD0iTTE1LjEgMTQuNGMwIC41LjkgMSAxLjkgMSAxLjEgMCAxLjktLjQgMS45LTEgMC0uNS0uOS0xLTEuOS0xLTEgMC0xLjkuNS0xLjkgMXpNOS43IDE0LjRjMCAuNS44IDEgMS45IDEgMSAwIDEuOS0uNCAxLjktMXMtLjgtMS0xLjktMWMtMS4xLjEtMS45LjUtMS45IDF6Ii8+PC9nPjxwYXRoIGZpbGw9IiMyMzFGMjAiIGQ9Ik0yMy44IDEwLjVWNmMuMS0zLjYgMS40LTUuMS40LTUuMy0xLS4yLTMuMi0uNi03LjgtLjYtNC4xIDAtNy4yLjUtOC4yLjZDNy4zIDEgOSAzLjkgOS4zIDZjLjEgMSAuMSAyLjUuMSAzLjgtMy4zLjUtNS4zIDEuNy01LjcgMi44aDI2LjZzLS4zLTEuMS02LjUtMi4xeiIvPjxwYXRoIGZpbGw9IiMzNTM0MzMiIGQ9Ik0xMi44IDIyLjRjMy4xIDIuOCAxMC40IDIuMyAxMC45LTIuMS4xLTEuMy0uNS0uMy0xLjEuMS0uOS42LTIuNS42LTMuNCAwLTEuNS0xLTQuMS00LjEtNi40LTEuOC0yLjQtMi4zLTUgLjgtNi41IDEuOC0uOS42LTIuNi42LTMuNSAwLS42LS40LTEuMi0xLjMtMS4xLS4xLjUgNC40IDcuOSA0LjkgMTEuMSAyLjF6Ii8+PC9nPjwvc3ZnPg==") no-repeat center; } } } From 44694ba617946fcd316110ce063b2562a8049095 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 8 May 2015 21:42:27 +0200 Subject: [PATCH 234/593] Added possibility to add series configuration on line chart to override specific options on series level, fixes #289, fixes #168 --- src/scripts/charts/line.js | 17 ++++++++++++----- src/scripts/core.js | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 162fee66..fda8f696 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -197,8 +197,15 @@ }); }.bind(this)); - var smoothing = typeof options.lineSmooth === 'function' ? - options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()); + var seriesOptions = { + lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'), + showPoint: Chartist.getSeriesOption(series, options, 'showPoint'), + showLine: Chartist.getSeriesOption(series, options, 'showLine'), + showArea: Chartist.getSeriesOption(series, options, 'showArea') + }; + + var smoothing = typeof seriesOptions.lineSmooth === 'function' ? + seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()); // Interpolating path where pathData will be used to annotate each path element so we can trace back the original // index, value and meta data var path = smoothing(pathCoordinates, pathData); @@ -206,7 +213,7 @@ // If we should show points we need to create them now to avoid secondary loop // Points are drawn from the pathElements returned by the interpolation function // Small offset for Firefox to render squares correctly - if (options.showPoint) { + if (seriesOptions.showPoint) { path.pathElements.forEach(function(pathElement) { var point = seriesGroups[seriesIndex].elem('line', { @@ -234,7 +241,7 @@ }.bind(this)); } - if(options.showLine) { + if(seriesOptions.showLine) { var line = seriesGroups[seriesIndex].elem('path', { d: path.stringify() }, options.classNames.line, true).attr({ @@ -254,7 +261,7 @@ }); } - if(options.showArea) { + if(seriesOptions.showArea) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); diff --git a/src/scripts/core.js b/src/scripts/core.js index 0033e7f1..4c8b006b 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -712,6 +712,24 @@ var Chartist = { }); }; + /** + * Helper to read series specific options from options object. It automatically falls back to the global option if + * there is no option in the series options. + * + * @param {Object} series Series object + * @param {Object} options Chartist options object + * @param {string} key The options key that should be used to obtain the options + * @returns {*} + */ + Chartist.getSeriesOption = function(series, options, key) { + if(series.name && options.series && options.series[series.name]) { + var seriesOptions = options.series[series.name]; + return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key]; + } else { + return options[key]; + } + }; + /** * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches * From acb2370fa3746d97086f1d9f366d34f33e5a612d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 9 May 2015 11:56:52 +0200 Subject: [PATCH 235/593] Refactored and simplified axis creation, also includes updated CSS label handling --- src/scripts/axes/axis.js | 4 +- src/scripts/axes/linear-scale-axis.js | 4 +- src/scripts/axes/step-axis.js | 4 +- src/scripts/charts/bar.js | 33 ------------- src/scripts/charts/line.js | 22 +-------- src/scripts/core.js | 32 +++++++++++-- src/styles/chartist.scss | 52 +++++++++++++++++---- src/styles/settings/_chartist-settings.scss | 9 ++-- 8 files changed, 81 insertions(+), 79 deletions(-) diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 4877a887..4a586891 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -26,14 +26,12 @@ } }; - function Axis(units, chartRect, transform, labelOffset, options) { + function Axis(units, chartRect, options) { this.units = units; this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; this.chartRect = chartRect; this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; this.gridOffset = chartRect[units.rectOffset]; - this.transform = transform; - this.labelOffset = labelOffset; this.options = options; } diff --git a/src/scripts/axes/linear-scale-axis.js b/src/scripts/axes/linear-scale-axis.js index 7c5d55dd..b51da419 100644 --- a/src/scripts/axes/linear-scale-axis.js +++ b/src/scripts/axes/linear-scale-axis.js @@ -7,12 +7,10 @@ (function (window, document, Chartist) { 'use strict'; - function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) { + function LinearScaleAxis(axisUnit, chartRect, options) { Chartist.LinearScaleAxis.super.constructor.call(this, axisUnit, chartRect, - transform, - labelOffset, options); this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index d84b647c..10c224bb 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -7,12 +7,10 @@ (function (window, document, Chartist) { 'use strict'; - function StepAxis(axisUnit, chartRect, transform, labelOffset, options) { + function StepAxis(axisUnit, chartRect, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, chartRect, - transform, - labelOffset, options); this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index d7b00ec0..06ce7464 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -89,7 +89,6 @@ function createChart(options) { var seriesGroups = [], normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), - normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding), highLow; // Create new svg element @@ -125,14 +124,6 @@ labelAxis = axisY = new Chartist.StepAxis( Chartist.Axis.units.y, chartRect, - function timeAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length - }, { stepCount: this.data.labels.length, stretch: options.fullHeight @@ -142,14 +133,6 @@ valueAxis = axisX = new Chartist.LinearScaleAxis( Chartist.Axis.units.x, chartRect, - function valueAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, { highLow: highLow, scaleMinSpace: options.axisX.scaleMinSpace, @@ -160,14 +143,6 @@ labelAxis = axisX = new Chartist.StepAxis( Chartist.Axis.units.x, chartRect, - function timeAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, { stepCount: this.data.labels.length } @@ -176,14 +151,6 @@ valueAxis = axisY = new Chartist.LinearScaleAxis( Chartist.Axis.units.y, chartRect, - function valueAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) - }, { highLow: highLow, scaleMinSpace: options.axisY.scaleMinSpace, diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index fda8f696..acf61966 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -94,28 +94,18 @@ * */ function createChart(options) { - var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), - normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding); + var seriesGroups = []; + var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); - var highLow = Chartist.getHighLow(normalizedData, options); var axisX = new Chartist.StepAxis( Chartist.Axis.units.x, chartRect, - function xAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, { stepCount: this.data.labels.length, stretch: options.fullWidth @@ -125,14 +115,6 @@ var axisY = new Chartist.LinearScaleAxis( Chartist.Axis.units.y, chartRect, - function yAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) - }, { highLow: highLow, scaleMinSpace: options.axisY.scaleMinSpace diff --git a/src/scripts/core.js b/src/scripts/core.js index 4c8b006b..4a87d12c 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -587,6 +587,7 @@ var Chartist = { y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom), x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset), y2: normalizedPadding.top, + padding: normalizedPadding, width: function () { return this.x2 - this.x1; }, @@ -651,10 +652,16 @@ var Chartist = { positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; positionalData[axis.units.len] = projectedValue.len; - positionalData[axis.counterUnits.len] = axisOffset; + positionalData[axis.counterUnits.len] = axisOffset - 10; if(useForeignObject) { - var content = '' + labels[index] + ''; + // 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] + ''; + labelElement = group.foreignObject(content, Chartist.extend({ style: 'overflow: visible;' }, positionalData)); @@ -687,15 +694,32 @@ var Chartist = { */ Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { var axisOptions = options['axis' + axis.units.pos.toUpperCase()], - projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform), + projectedValues = data.map(axis.projectValue.bind(axis)), labelValues = data.map(axisOptions.labelInterpolationFnc); projectedValues.forEach(function(projectedValue, index) { + var labelOffset = { + x: 0, + y: 0 + }; + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) if(!labelValues[index] && labelValues[index] !== 0) { return; } + // Transform to global coordinates using the chartRect + // We also need to set the label offset for the createLabel function + if(axis.units.pos === 'x') { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + labelOffset.x = options.axisX.labelOffset.x; + labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } else { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10; + labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? chartRect.height() / labelValues.length : 0); + } + if(axisOptions.showGrid) { Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ options.classNames.grid, @@ -704,7 +728,7 @@ var Chartist = { } if(axisOptions.showLabel) { - Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [ + Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [ options.classNames.label, options.classNames[axis.units.dir] ], useForeignObject, eventEmitter); diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index 75219208..bb41bab4 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -28,14 +28,36 @@ } } -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align) { +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) { + // Fallback to block display: block; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + -webkit-box-align: $ct-text-align; + -webkit-align-items: $ct-text-align; + -ms-flex-align: $ct-text-align; + align-items: $ct-text-align; + -webkit-box-pack: $ct-text-justify; + -webkit-justify-content: $ct-text-justify; + -ms-flex-pack: $ct-text-justify; + justify-content: $ct-text-justify; + // Fallback to text-align for non-flex browsers + @if($ct-text-justify == 'flex-start') { + text-align: left; + } @else if ($ct-text-justify == 'flex-end') { + text-align: right; + } @else { + text-align: center; + } + width: 100%; height: 100%; fill: $ct-text-color; color: $ct-text-color; font-size: $ct-text-size; - text-align: $ct-text-align; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { @@ -86,31 +108,41 @@ } } -@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { +@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-horizontal-text-justify: $ct-horizontal-text-justify, $ct-vertical-text-justify: $ct-vertical-text-justify, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { .#{$ct-class-label} { @include ct-chart-label($ct-text-color, $ct-text-size); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; } .#{$ct-class-label}.#{$ct-class-horizontal} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align); + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align, $ct-horizontal-text-justify); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; } .#{$ct-class-label}.#{$ct-class-vertical} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align); + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align, $ct-vertical-text-justify); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; } .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal} { - text-align: center; + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align, center); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; } .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal} { - text-align: left; + @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; } .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical} { - display: flex; - align-items: center; - justify-content: flex-end; + @include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; } .#{$ct-class-grid} { diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss index bca20d7d..a2164e31 100644 --- a/src/styles/settings/_chartist-settings.scss +++ b/src/styles/settings/_chartist-settings.scss @@ -26,9 +26,12 @@ $ct-container-ratio: (1/1.618) !default; // Text styles for labels $ct-text-color: rgba(0, 0, 0, 0.4) !default; $ct-text-size: 0.75rem !default; -$ct-text-align: left !default; -$ct-horizontal-text-align: left !default; -$ct-vertical-text-align: right !default; +$ct-text-align: flex-start !default; +$ct-text-justify: flex-start !default; +$ct-horizontal-text-align: flex-start !default; +$ct-horizontal-text-justify: flex-start !default; +$ct-vertical-text-align: flex-end !default; +$ct-vertical-text-justify: flex-end !default; // Grid styles $ct-grid-color: rgba(0, 0, 0, 0.2) !default; From d1f20d563cebfcf5d036affb0a8cb866d076ee04 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 9 May 2015 12:12:31 +0200 Subject: [PATCH 236/593] Reformatting axis creation --- src/scripts/charts/bar.js | 50 +++++++++++++------------------------- src/scripts/charts/line.js | 24 ++++++------------ 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 06ce7464..1c49418f 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -121,42 +121,26 @@ axisY; if(options.horizontalBars) { - labelAxis = axisY = new Chartist.StepAxis( - Chartist.Axis.units.y, - chartRect, - { - stepCount: this.data.labels.length, - stretch: options.fullHeight - } - ); + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, { + stepCount: this.data.labels.length, + stretch: options.fullHeight + }); - valueAxis = axisX = new Chartist.LinearScaleAxis( - Chartist.Axis.units.x, - chartRect, - { - highLow: highLow, - scaleMinSpace: options.axisX.scaleMinSpace, - referenceValue: 0 - } - ); + valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, { + highLow: highLow, + scaleMinSpace: options.axisX.scaleMinSpace, + referenceValue: 0 + }); } else { - labelAxis = axisX = new Chartist.StepAxis( - Chartist.Axis.units.x, - chartRect, - { - stepCount: this.data.labels.length - } - ); + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { + stepCount: this.data.labels.length + }); - valueAxis = axisY = new Chartist.LinearScaleAxis( - Chartist.Axis.units.y, - chartRect, - { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - referenceValue: 0 - } - ); + valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace, + referenceValue: 0 + }); } // Start drawing diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index acf61966..91c6a27f 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -103,23 +103,15 @@ var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var highLow = Chartist.getHighLow(normalizedData, options); - var axisX = new Chartist.StepAxis( - Chartist.Axis.units.x, - chartRect, - { - stepCount: this.data.labels.length, - stretch: options.fullWidth - } - ); + var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { + stepCount: this.data.labels.length, + stretch: options.fullWidth + }); - var axisY = new Chartist.LinearScaleAxis( - Chartist.Axis.units.y, - chartRect, - { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace - } - ); + var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace + }); // Start drawing var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), From 6c3a638a331706eb5fbcd904cbdfbb78c20c29ec Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 9 May 2015 19:24:25 +0200 Subject: [PATCH 237/593] charts: Optimized usage of chart space and optimized scale step narrowing --- src/scripts/axes/linear-scale-axis.js | 2 +- src/scripts/charts/bar.js | 11 ++++++++--- src/scripts/charts/line.js | 13 ++++++++++--- src/scripts/core.js | 22 ++++++++++------------ 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/scripts/axes/linear-scale-axis.js b/src/scripts/axes/linear-scale-axis.js index b51da419..bf5e538a 100644 --- a/src/scripts/axes/linear-scale-axis.js +++ b/src/scripts/axes/linear-scale-axis.js @@ -18,7 +18,7 @@ function projectValue(value) { return { - pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step), + pos: this.axisLength * (value - this.bounds.min) / this.bounds.range, len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) }; } diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 1c49418f..e4f1a1e2 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -29,7 +29,7 @@ // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum width in pixel of the scale steps - scaleMinSpace: 40 + scaleMinSpace: 20 }, // Options for Y-Axis axisY: { @@ -38,7 +38,7 @@ // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, - y: 0 + y: 5 }, // If labels should be shown or not showLabel: true, @@ -58,7 +58,12 @@ // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, // 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} - chartPadding: 5, + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, // If set to true this property will cause the series bars to be stacked and 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. diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 91c6a27f..b9c5432c 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -29,7 +29,9 @@ // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop + labelInterpolationFnc: Chartist.noop, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20 }, // Options for Y-Axis axisY: { @@ -38,7 +40,7 @@ // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, - y: 0 + y: 5 }, // If labels should be shown or not showLabel: true, @@ -68,7 +70,12 @@ // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, // 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} - chartPadding: 5, + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, // 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. fullWidth: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. diff --git a/src/scripts/core.js b/src/scripts/core.js index 4a87d12c..f1921f56 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -497,10 +497,10 @@ var Chartist = { bounds.valueRange = bounds.high - bounds.low; bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); - bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.range = bounds.max - bounds.min; bounds.step = Math.pow(10, bounds.oom); + bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step; + bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step; + bounds.range = bounds.max - bounds.min; bounds.numberOfSteps = Math.round(bounds.range / bounds.step); // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace @@ -508,6 +508,7 @@ var Chartist = { var length = Chartist.projectLength(axisLength, bounds.step, bounds), scaleUp = length < scaleMinSpace; + // Trying to divide or multiply by 2 and find the best step value while (true) { if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { bounds.step *= 2; @@ -521,14 +522,11 @@ var Chartist = { // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - if (i + bounds.step < bounds.low) { - newMin += bounds.step; - } - - if (i - bounds.step >= bounds.high) { - newMax -= bounds.step; - } + while(newMin + bounds.step <= bounds.low) { + newMin += bounds.step; + } + while(newMax - bounds.step >= bounds.high) { + newMax -= bounds.step; } bounds.min = newMin; bounds.max = newMax; @@ -717,7 +715,7 @@ var Chartist = { } else { projectedValue.pos = chartRect.y1 - projectedValue.pos; labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10; - labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? chartRect.height() / labelValues.length : 0); + labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 0); } if(axisOptions.showGrid) { From 71c2ef086dac29b2d3c0fc3c7d6b87885449d76f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 9 May 2015 19:48:27 +0200 Subject: [PATCH 238/593] Added option to only use integer numbers in linear scale axis, fixes #77 --- src/scripts/axes/linear-scale-axis.js | 2 +- src/scripts/charts/bar.js | 12 ++++- src/scripts/charts/line.js | 11 ++-- src/scripts/core.js | 74 ++++++++++++++++++++++----- 4 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/scripts/axes/linear-scale-axis.js b/src/scripts/axes/linear-scale-axis.js index bf5e538a..d58c3137 100644 --- a/src/scripts/axes/linear-scale-axis.js +++ b/src/scripts/axes/linear-scale-axis.js @@ -13,7 +13,7 @@ chartRect, options); - this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); + this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger); } function projectValue(value) { diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index e4f1a1e2..648d24b9 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -29,7 +29,9 @@ // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum width in pixel of the scale steps - scaleMinSpace: 20 + scaleMinSpace: 30, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Options for Y-Axis axisY: { @@ -47,7 +49,9 @@ // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20 + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, @@ -57,6 +61,8 @@ high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false, // 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} chartPadding: { top: 15, @@ -134,6 +140,7 @@ valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, { highLow: highLow, scaleMinSpace: options.axisX.scaleMinSpace, + onlyInteger: options.axisX.onlyInteger, referenceValue: 0 }); } else { @@ -144,6 +151,7 @@ valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { highLow: highLow, scaleMinSpace: options.axisY.scaleMinSpace, + onlyInteger: options.axisY.onlyInteger, referenceValue: 0 }); } diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index b9c5432c..edcf8377 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -31,7 +31,9 @@ // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20 + scaleMinSpace: 30, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Options for Y-Axis axisY: { @@ -49,7 +51,9 @@ // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20 + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, @@ -117,7 +121,8 @@ var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace + scaleMinSpace: options.axisY.scaleMinSpace, + onlyInteger: options.axisY.onlyInteger }); // Start drawing diff --git a/src/scripts/core.js b/src/scripts/core.js index f1921f56..16ad941a 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -468,6 +468,40 @@ var Chartist = { return highLow; }; + /** + * 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. + * + * @memberof Chartist.Core + * @param {Number} num An integer number where the smallest factor should be searched for + * @returns {Number} The smallest integer factor of the parameter num. + */ + Chartist.rho = function(num) { + function gcd(p, q) { + if (p % q === 0) { + return q; + } else { + return gcd(q, p % q); + } + } + + function f(x) { + return x * x + 1; + } + + var x1 = 2, x2 = 2, divisor; + if (num % 2 === 0) { + return 2; + } + + do { + x1 = f(x1) % num; + x2 = f(f(x2)) % num; + divisor = gcd(Math.abs(x1 - x2), num); + } while (divisor === 1); + + return divisor; + }; + /** * Calculate and retrieve all the bounds for the chart and return them in one array * @@ -476,9 +510,10 @@ var Chartist = { * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. * @param {Number} scaleMinSpace The minimum projected length a step should result in * @param {Number} referenceValue The reference value for the chart. + * @param {Boolean} onlyInteger * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) { + Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue, onlyInteger) { var i, newMin, newMax, @@ -505,17 +540,32 @@ var Chartist = { // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace // If we are already below the scaleMinSpace value we will scale up - var length = Chartist.projectLength(axisLength, bounds.step, bounds), - scaleUp = length < scaleMinSpace; - - // Trying to divide or multiply by 2 and find the best step value - while (true) { - if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { - bounds.step *= 2; - } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { - bounds.step /= 2; - } else { - break; + var length = Chartist.projectLength(axisLength, bounds.step, bounds); + var scaleUp = length < scaleMinSpace; + var smallestFactor = onlyInteger ? Chartist.rho(bounds.range) : 0; + + // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1 + if(onlyInteger && Chartist.projectLength(axisLength, 1, bounds) >= scaleMinSpace) { + bounds.step = 1; + } else if(onlyInteger && smallestFactor < bounds.step && Chartist.projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) { + // If step 1 was too small, we can try the smallest factor of range + // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor + // is larger than the scaleMinSpace we should go for it. + bounds.step = smallestFactor; + } else { + // Trying to divide or multiply by 2 and find the best step value + while (true) { + if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { + bounds.step /= 2; + if(onlyInteger && bounds.step % 1 !== 0) { + bounds.step *= 2; + break; + } + } else { + break; + } } } From 40a16f0cca5f83ac5404d8fc443ee3fa437698a4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 9 May 2015 23:59:17 +0200 Subject: [PATCH 239/593] Added option for label placement and refactored label positioning code, fixes #302 --- src/scripts/charts/bar.js | 10 ++- src/scripts/charts/line.js | 10 ++- src/scripts/core.js | 80 +++++++++++++++------ src/styles/chartist.scss | 77 ++++++++++++++------ src/styles/settings/_chartist-settings.scss | 7 +- 5 files changed, 134 insertions(+), 50 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 648d24b9..1a9309fd 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -17,6 +17,8 @@ axisX: { // The offset of the chart drawing area to the border of the container offset: 30, + // 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. + position: 'end', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, @@ -37,10 +39,12 @@ axisY: { // The offset of the chart drawing area to the border of the container offset: 40, + // 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. + position: 'start', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, - y: 5 + y: 0 }, // If labels should be shown or not showLabel: true, @@ -89,7 +93,9 @@ grid: 'ct-grid', gridGroup: 'ct-grids', vertical: 'ct-vertical', - horizontal: 'ct-horizontal' + horizontal: 'ct-horizontal', + start: 'ct-start', + end: 'ct-end' } }; diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index edcf8377..4c4428aa 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -19,6 +19,8 @@ axisX: { // The offset of the labels to the chart area offset: 30, + // 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. + position: 'end', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, @@ -39,10 +41,12 @@ axisY: { // The offset of the labels to the chart area offset: 40, + // 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. + position: 'start', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, - y: 5 + y: 0 }, // If labels should be shown or not showLabel: true, @@ -96,7 +100,9 @@ grid: 'ct-grid', gridGroup: 'ct-grids', vertical: 'ct-vertical', - horizontal: 'ct-horizontal' + horizontal: 'ct-horizontal', + start: 'ct-start', + end: 'ct-end' } }; diff --git a/src/scripts/core.js b/src/scripts/core.js index 16ad941a..4c05f03e 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -619,22 +619,19 @@ var Chartist = { * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ Chartist.createChartRect = function (svg, options, fallbackPadding) { - var yOffset = options.axisY ? options.axisY.offset || 0 : 0, - xOffset = options.axisX ? options.axisX.offset || 0 : 0, - // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 - w = svg.width() || Chartist.stripUnit(options.width) || 0, - h = svg.height() || Chartist.stripUnit(options.height) || 0, - normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); + var hasAxis = !!(options.axisX || options.axisY); + var yAxisOffset = hasAxis ? options.axisY.offset : 0; + var xAxisOffset = hasAxis ? options.axisX.offset : 0; + // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 + var width = svg.width() || Chartist.stripUnit(options.width) || 0; + var height = svg.height() || Chartist.stripUnit(options.height) || 0; + var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust - w = Math.max(w, xOffset + normalizedPadding.left + normalizedPadding.right); - h = Math.max(h, yOffset + normalizedPadding.top + normalizedPadding.bottom); + width = Math.max(width, xAxisOffset + normalizedPadding.left + normalizedPadding.right); + height = Math.max(height, yAxisOffset + normalizedPadding.top + normalizedPadding.bottom); - return { - x1: normalizedPadding.left + yOffset, - y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom), - x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset), - y2: normalizedPadding.top, + var chartRect = { padding: normalizedPadding, width: function () { return this.x2 - this.x1; @@ -643,6 +640,31 @@ var Chartist = { return this.y1 - this.y2; } }; + + if(hasAxis) { + if (options.axisX.position === 'start') { + chartRect.y2 = normalizedPadding.top + xAxisOffset; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } else { + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1); + } + + if (options.axisY.position === 'start') { + chartRect.x1 = normalizedPadding.left + yAxisOffset; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1); + } + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } + + return chartRect; }; /** @@ -695,8 +717,9 @@ var Chartist = { * @param eventEmitter */ Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { - var labelElement, - positionalData = {}; + var labelElement; + var positionalData = {}; + positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; positionalData[axis.units.len] = projectedValue.len; @@ -741,9 +764,9 @@ var Chartist = { * @param eventEmitter */ Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { - var axisOptions = options['axis' + axis.units.pos.toUpperCase()], - projectedValues = data.map(axis.projectValue.bind(axis)), - labelValues = data.map(axisOptions.labelInterpolationFnc); + var axisOptions = options['axis' + axis.units.pos.toUpperCase()]; + var projectedValues = data.map(axis.projectValue.bind(axis)); + var labelValues = data.map(axisOptions.labelInterpolationFnc); projectedValues.forEach(function(projectedValue, index) { var labelOffset = { @@ -761,11 +784,25 @@ var Chartist = { if(axis.units.pos === 'x') { projectedValue.pos = chartRect.x1 + projectedValue.pos; labelOffset.x = options.axisX.labelOffset.x; - labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + + // If the labels should be positioned in start position (top side for vertical axis) we need to set a + // different offset as for positioned with end (bottom) + if(options.axisX.position === 'start') { + labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } else { + labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } } else { projectedValue.pos = chartRect.y1 - projectedValue.pos; - labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10; labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 0); + + // If the labels should be positioned in start position (left side for horizontal axis) we need to set a + // different offset as for positioned with end (right side) + if(options.axisY.position === 'start') { + labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10; + } else { + labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10; + } } if(axisOptions.showGrid) { @@ -778,7 +815,8 @@ var Chartist = { if(axisOptions.showLabel) { Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [ options.classNames.label, - options.classNames[axis.units.dir] + options.classNames[axis.units.dir], + options.classNames[axisOptions.position] ], useForeignObject, eventEmitter); } }); diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index bb41bab4..4b2407d8 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -28,14 +28,7 @@ } } -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) { - // Fallback to block - display: block; - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; +@mixin ct-align-justify($ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) { -webkit-box-align: $ct-text-align; -webkit-align-items: $ct-text-align; -ms-flex-align: $ct-text-align; @@ -52,12 +45,21 @@ } @else { text-align: center; } +} + +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) { + // Fallback to block + display: block; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; - width: 100%; - height: 100%; fill: $ct-text-color; color: $ct-text-color; font-size: $ct-text-size; + line-height: $ct-text-line-height; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { @@ -108,39 +110,72 @@ } } -@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-horizontal-text-justify: $ct-horizontal-text-justify, $ct-vertical-text-justify: $ct-vertical-text-justify, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { +@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { + .#{$ct-class-label} { @include ct-chart-label($ct-text-color, $ct-text-size); + @include ct-align-justify($ct-text-align, $ct-text-justify); // Fallback for browsers that don't support foreignObjects text-anchor: start; } - .#{$ct-class-label}.#{$ct-class-horizontal} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align, $ct-horizontal-text-justify); + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-start); // Fallback for browsers that don't support foreignObjects text-anchor: start; } - .#{$ct-class-label}.#{$ct-class-vertical} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align, $ct-vertical-text-justify); + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-end); // Fallback for browsers that don't support foreignObjects text-anchor: end; } - .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align, center); + .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { + @include ct-align-justify(flex-end, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, center); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, center); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-start); // Fallback for browsers that don't support foreignObjects text-anchor: start; } - .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align, flex-start); + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, flex-start); // Fallback for browsers that don't support foreignObjects text-anchor: start; } - .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical} { - @include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify); + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { + //@include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify); + @include ct-align-justify(center, flex-end); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { + @include ct-align-justify(center, flex-start); // Fallback for browsers that don't support foreignObjects text-anchor: end; } diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss index a2164e31..af242f49 100644 --- a/src/styles/settings/_chartist-settings.scss +++ b/src/styles/settings/_chartist-settings.scss @@ -19,6 +19,8 @@ $ct-class-donut: ct-donut !default; $ct-class-grid: ct-grid !default; $ct-class-vertical: ct-vertical !default; $ct-class-horizontal: ct-horizontal !default; +$ct-class-start: ct-start !default; +$ct-class-end: ct-end !default; // Container ratio $ct-container-ratio: (1/1.618) !default; @@ -28,10 +30,7 @@ $ct-text-color: rgba(0, 0, 0, 0.4) !default; $ct-text-size: 0.75rem !default; $ct-text-align: flex-start !default; $ct-text-justify: flex-start !default; -$ct-horizontal-text-align: flex-start !default; -$ct-horizontal-text-justify: flex-start !default; -$ct-vertical-text-align: flex-end !default; -$ct-vertical-text-justify: flex-end !default; +$ct-text-line-height: 1; // Grid styles $ct-grid-color: rgba(0, 0, 0, 0.2) !default; From e10a58feae3b444dbd2206309f0353c16b914128 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 01:21:29 +0200 Subject: [PATCH 240/593] Added new option to bar charts to allow a series distribution and use a simple one dimensional array for data, fixes #209 --- src/scripts/charts/bar.js | 88 ++++++++++++++++++++++++++++++++------- src/scripts/core.js | 2 +- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 1a9309fd..6455564c 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -80,6 +80,8 @@ stackBars: false, // 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. horizontalBars: false, + // 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. + distributeSeries: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. reverseData: false, // Override the class names that get used to generate the SVG structure of the chart @@ -104,9 +106,12 @@ * */ function createChart(options) { - var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), - highLow; + var seriesGroups = []; + var data = Chartist.getDataArray(this.data, options.reverseData); + var normalizedData = options.distributeSeries ? data.map(function(value) { + return [value]; + }) : Chartist.normalizeDataArray(data, this.data.labels.length); + var highLow; // Create new svg element this.svg = Chartist.createSvg( @@ -133,14 +138,30 @@ var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, + labelAxisStepCount, labelAxis, axisX, axisY; + // We need to set step count based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we need to use the one dimensional series array + // length as step count for the label axis + labelAxisStepCount = normalizedData.length; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore set step + // count to 1 + labelAxisStepCount = 1; + } else { + // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length + // as the bars are normalized + labelAxisStepCount = this.data.labels.length; + } + + // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, { - stepCount: this.data.labels.length, - stretch: options.fullHeight + stepCount: labelAxisStepCount }); valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, { @@ -151,7 +172,7 @@ }); } else { labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { - stepCount: this.data.labels.length + stepCount: labelAxisStepCount }); valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { @@ -197,7 +218,21 @@ // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. var biPol = seriesIndex - (this.data.series.length - 1) / 2, // Half of the period width between vertical grid lines used to position bars - periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2; + periodHalfLength; + + // We need to set periodHalfLength based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array + // which is the series count and divide by 2 + periodHalfLength = labelAxis.axisLength / normalizedData.length / 2; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis + // length by 2 + periodHalfLength = labelAxis.axisLength / 2; + } else { + // On regular bar charts we should just use the series length + periodHalfLength = labelAxis.axisLength / normalizedData[seriesIndex].length / 2; + } seriesGroups[seriesIndex] = this.svg.elem('g'); @@ -214,17 +249,42 @@ ].join(' ')); normalizedData[seriesIndex].forEach(function(value, valueIndex) { - var projected = { - x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos - }, + var projected, bar, - previousStack; + previousStack, + labelAxisValueIndex; + + // We need to set labelAxisValueIndex based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection + // on the step axis for label positioning + labelAxisValueIndex = seriesIndex; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use + // 0 for projection on the label step axis + labelAxisValueIndex = 0; + } else { + // On regular bar charts we just use the value index to project on the label step axis + labelAxisValueIndex = valueIndex; + } + + // We need to transform coordinates differently based on the chart layout + if(options.horizontalBars) { + projected = { + x: chartRect.x1 + valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos + }; + } else { + projected = { + x: chartRect.x1 + labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + } + } // Offset to center bar between grid lines projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); - // Using bi-polar offset for multiple series if no stacked bars are used - projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + // Using bi-polar offset for multiple series if no stacked bars or series distribution is used + projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); // Enter value in stacked bar values used to remember previous screen value for stacking up bars previousStack = stackedBarValues[valueIndex] || zeroPoint; diff --git a/src/scripts/core.js b/src/scripts/core.js index 4c05f03e..65143166 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -293,7 +293,7 @@ var Chartist = { for (var i = 0; i < data.series.length; i++) { if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { data.series[i].data.reverse(); - } else { + } else if(data.series[i] instanceof Array) { data.series[i].reverse(); } } From 0a027cf562cf051cc629abae45d5005c685d1f6a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 01:42:45 +0200 Subject: [PATCH 241/593] Fixed minor bug with label positioning issue in pie chart --- src/styles/chartist.scss | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index 4b2407d8..aaeb6953 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -47,7 +47,7 @@ } } -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) { +@mixin ct-flex() { // Fallback to block display: block; display: -webkit-box; @@ -55,7 +55,9 @@ display: -ms-flexbox; display: -webkit-flex; display: flex; +} +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) { fill: $ct-text-color; color: $ct-text-color; font-size: $ct-text-size; @@ -114,9 +116,11 @@ .#{$ct-class-label} { @include ct-chart-label($ct-text-color, $ct-text-size); - @include ct-align-justify($ct-text-align, $ct-text-justify); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; + } + + .#{$ct-class-chart-line} .#{$ct-class-label}, + .#{$ct-class-chart-bar} .#{$ct-class-label} { + @include ct-flex(); } .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { From da96ffc4bd8afc7b4565ffa496f7b495dd32f735 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 01:43:23 +0200 Subject: [PATCH 242/593] documentation: fixed chart on landing page after new rendering order --- site/scripts/chartist-guy.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/site/scripts/chartist-guy.js b/site/scripts/chartist-guy.js index 1fbf714f..e13ab038 100644 --- a/site/scripts/chartist-guy.js +++ b/site/scripts/chartist-guy.js @@ -5,7 +5,12 @@ var optionsChartistGuy = { width: 195, height: 137, - chartPadding: 10, + chartPadding: { + top: 15, + right: 10, + bottom: 10, + left: 10 + }, axisX: { offset: 15, showLabel: true, @@ -17,6 +22,9 @@ axisY: { offset: 25, showLabel: true, + labelOffset: { + y: 5 + }, showGrid: true, scaleMinSpace: 15, labelInterpolationFnc: function(n) { From b449c87673f3735cb2a176a6de5aa0c2f0f11d15 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 03:24:18 +0200 Subject: [PATCH 243/593] documentation: Added documentation for the new distributeSeries option as well as for the new series options overrides, fixes #312, fixes #312 --- site/data/pages/examples.yml | 22 ++++++++++++++++++++++ site/data/pages/getting-started.yml | 22 ++++++++++++++++++++++ site/partials/navigation.hbs | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index de16cec6..cea8b9f2 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -90,6 +90,18 @@ sections: things in Chartist, this can be customized easily! Check out the API Documentation for more smoothing options. + - type: live-example + data: + title: Series Overrides + level: 4 + id: example-line-series-override + classes: ct-golden-section + intro: > + By naming your series using the series object notation with a name property, you can enable the + individual configuration of series specific settings. showLine, showPoint, + showArea and even the smoothing function can be overriden per series! And guess what? + You can even override those series settings in the responsive configuration! Check the example code + for more details. - title: Bar chart examples level: 3 items: @@ -157,6 +169,16 @@ sections: intro: > As all settings of a chart can be customized with the responsive configuration override mechanism of Chartist, you can create a chart that adopts to every media condition! + - type: live-example + data: + title: Distributed series + level: 4 + id: example-bar-distributed-series + classes: ct-golden-section + intro: > + Sometime it's desired to have bar charts that show one bar per series distributed along the x-axis. If + this option is enabled, you need to make sure that you pass a single series array to Chartist that + contains the series values. In this example you can see T-shirt sales of a store categorized by size. - title: Pie chart examples level: 3 items: diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 4906a928..16102c21 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -381,6 +381,28 @@ sections: sure you include matchMedia.js as well as matchMedia.addListener.js as always both are needed to polyfill the full specification of window.matchMedia. + - type: sub-section + data: + title: Different configuration for different series + level: 4 + items: + - type: text + data: + text: > + Chartist also allows you to add specific configuration overrides for your series. This is useful + if you want to combine different looks for your series on the same chart. + - type: text + data: + text: > + You can even take this one step further by again overriding your series configuration in some + responsive settings overrides. This sounds complicated but it actually is very simple. Check the + example code with inline comments below to see how easy it is. + - type: example-chart + data: + id: example-line-series-override + classes: ct-golden-section + show-code-button: Show code + - title: Advanced level: 3 items: diff --git a/site/partials/navigation.hbs b/site/partials/navigation.hbs index 3d3f1dc4..ddf00f98 100644 --- a/site/partials/navigation.hbs +++ b/site/partials/navigation.hbs @@ -15,7 +15,7 @@ From 8e5cc2580452692e44ea1d774fbb0cf82f8c74a8 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 03:24:32 +0200 Subject: [PATCH 244/593] Removed unecessary setting --- src/scripts/charts/line.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 4c4428aa..e1d8647f 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -32,8 +32,6 @@ showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, - // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 30, // Use only integer values (whole numbers) for the scale steps onlyInteger: false }, From 21b49c8be2ff5159e4e8848bc5309e2b9ad3f408 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 03:26:54 +0200 Subject: [PATCH 245/593] documentation: Added missing examples --- .../example-bar-distributed-series.js | 6 +++ site/examples/example-line-series-override.js | 49 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 site/examples/example-bar-distributed-series.js create mode 100644 site/examples/example-line-series-override.js diff --git a/site/examples/example-bar-distributed-series.js b/site/examples/example-bar-distributed-series.js new file mode 100644 index 00000000..99f02ba6 --- /dev/null +++ b/site/examples/example-bar-distributed-series.js @@ -0,0 +1,6 @@ +new Chartist.Bar('.ct-chart', { + labels: ['XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL'], + series: [20, 60, 120, 200, 180, 20, 10] +}, { + distributeSeries: true +}); diff --git a/site/examples/example-line-series-override.js b/site/examples/example-line-series-override.js new file mode 100644 index 00000000..034039bf --- /dev/null +++ b/site/examples/example-line-series-override.js @@ -0,0 +1,49 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: ['1', '2', '3', '4', '5', '6', '7', '8'], + // Naming the series with the series object array notation + series: [{ + name: 'series-1', + data: [5, 2, -4, 2, 0, -2, 5, -3] + }, { + name: 'series-2', + data: [4, 3, 5, 3, 1, 3, 6, 4] + }, { + name: 'series-3', + data: [2, 4, 3, 1, 4, 5, 3, 2] + }] +}, { + fullWidth: true, + // Within the series options you can use the series names + // to specify configuration that will only be used for the + // specific series. + series: { + 'series-1': { + lineSmooth: Chartist.Interpolation.step() + }, + 'series-2': { + lineSmooth: Chartist.Interpolation.simple(), + showArea: true + }, + 'series-3': { + showPoint: false + } + } +}, [ + // You can even use responsive configuration overrides to + // customize your series configuration even further! + ['screen and (max-width: 320px)', { + series: { + 'series-1': { + lineSmooth: Chartist.Interpolation.none() + }, + 'series-2': { + lineSmooth: Chartist.Interpolation.none(), + showArea: false + }, + 'series-3': { + lineSmooth: Chartist.Interpolation.none(), + showPoint: true + } + } + }] +]); From ad1fdfb702725654f4cdba182dfe744703f2361e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 03:40:06 +0200 Subject: [PATCH 246/593] documentation: Added example for data holes, fixes #310 --- site/data/pages/examples.yml | 10 ++++++++++ site/examples/example-line-data-holes.js | 14 ++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 site/examples/example-line-data-holes.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index cea8b9f2..fc44757f 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -9,6 +9,16 @@ sections: id: simple-line-chart classes: ct-golden-section intro: An example of a simple line chart with three series. You can edit this example in realtime. + - type: live-example + data: + title: Holes in data + level: 4 + id: example-line-data-holes + classes: ct-golden-section + intro: > + Chartist does not freak out if you have holes in your data. Instead it will render the lines in + segments and handles these holes gracefully. This also allows you to introduce a line at a later + point or to terminate the series before others. - type: live-example data: title: Line scatter diagram with responsive settings diff --git a/site/examples/example-line-data-holes.js b/site/examples/example-line-data-holes.js new file mode 100644 index 00000000..526f300f --- /dev/null +++ b/site/examples/example-line-data-holes.js @@ -0,0 +1,14 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + series: [ + [5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9], + [10, 15, null, 12, null, 10, 12, 15, null, null, 12, null, 14, null, null, null], + [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null] + ] +}, { + fullWidth: true, + chartPadding: { + right: 10 + }, + low: 0 +}); From 1e044abc0f79246a3ee3b5f2fe3cb7b961e1b835 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 04:00:18 +0200 Subject: [PATCH 247/593] documentation: Added more examples with latest features --- site/data/pages/examples.yml | 20 ++++++++++++++++++++ site/examples/example-bar-label-position.js | 16 ++++++++++++++++ site/examples/example-line-only-integer.js | 18 ++++++++++++++++++ site/partials/side-navigation.hbs | 4 ++-- 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 site/examples/example-bar-label-position.js create mode 100644 site/examples/example-line-only-integer.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index fc44757f..4f4f7301 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -19,6 +19,16 @@ sections: Chartist does not freak out if you have holes in your data. Instead it will render the lines in segments and handles these holes gracefully. This also allows you to introduce a line at a later point or to terminate the series before others. + - type: live-example + data: + title: Only whole numbers + level: 4 + id: example-line-only-integer + classes: ct-golden-section + intro: > + You're dealing with series that contain only whole numbers? It looks weird that Chartist is creating + a scale that contains fractions even if your data does not? No problem! Tell the Chartist guy to + only use integers and he'll do the math! - type: live-example data: title: Line scatter diagram with responsive settings @@ -189,6 +199,16 @@ sections: Sometime it's desired to have bar charts that show one bar per series distributed along the x-axis. If this option is enabled, you need to make sure that you pass a single series array to Chartist that contains the series values. In this example you can see T-shirt sales of a store categorized by size. + - type: live-example + data: + title: Label placement + level: 4 + id: example-bar-label-position + classes: ct-golden-section + intro: > + You can change the position of the labels on line and bar charts easily by using the position + option inside of the axis configuration. + - title: Pie chart examples level: 3 items: diff --git a/site/examples/example-bar-label-position.js b/site/examples/example-bar-label-position.js new file mode 100644 index 00000000..19b93d5c --- /dev/null +++ b/site/examples/example-bar-label-position.js @@ -0,0 +1,16 @@ +new Chartist.Bar('.ct-chart', { + labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 4, 3, 7, 5, 10, 3], + [3, 2, 9, 5, 4, 6, 4] + ] +}, { + axisX: { + // On the x-axis start means top and end means bottom + position: 'start' + }, + axisY: { + // On the y-axis start means left and end means right + position: 'end' + } +}); diff --git a/site/examples/example-line-only-integer.js b/site/examples/example-line-only-integer.js new file mode 100644 index 00000000..2157bb9d --- /dev/null +++ b/site/examples/example-line-only-integer.js @@ -0,0 +1,18 @@ +new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8], + series: [ + [1, 2, 3, 1, -2, 0, 1, 0], + [-2, -1, -2, -1, -3, -1, -2, -1], + [0, 0, 0, 1, 2, 3, 2, 1], + [3, 2, 1, 0.5, 1, 0, -1, -3] + ] +}, { + high: 3, + low: -3, + fullWidth: true, + // As this is axis specific we need to tell Chartist to use whole numbers only on the concerned axis + axisY: { + onlyInteger: true, + offset: 20 + } +}); diff --git a/site/partials/side-navigation.hbs b/site/partials/side-navigation.hbs index 9d9d3f90..a6be4d7a 100644 --- a/site/partials/side-navigation.hbs +++ b/site/partials/side-navigation.hbs @@ -1,4 +1,4 @@ - From c103ad797ca0400ce19798771550644ac1f56906 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 04:36:48 +0200 Subject: [PATCH 248/593] documentation: Added library statement to landing page --- site/layouts/landing.hbs | 3 +++ site/styles/_landing.scss | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/site/layouts/landing.hbs b/site/layouts/landing.hbs index b54704a8..fe6bc549 100644 --- a/site/layouts/landing.hbs +++ b/site/layouts/landing.hbs @@ -11,6 +11,9 @@ layout: default +
    + Only 10KB (Gzip) with no dependencies! +
    Download Contribute diff --git a/site/styles/_landing.scss b/site/styles/_landing.scss index 8a1a1269..c5fc8317 100644 --- a/site/styles/_landing.scss +++ b/site/styles/_landing.scss @@ -27,6 +27,24 @@ } } + .library-statement { + text-transform: uppercase; + font-size: rem-calc(nth($modular-scale, 5)); + margin: 0; + display: inline-block; + width: 100%; + font-weight: 700; + color: white; + + @include text-shadow(1px 1px mix(black, $color-yellow, 15%), 2px 2px mix(black, $color-yellow, 15%)); + + padding-bottom: $column-gutter; + + .important { + text-decoration: underline; + } + } + > .limiter { position: relative; max-width: 480px; From 6399391df3e56bb7406e93e68748eafad4154011 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 04:39:58 +0200 Subject: [PATCH 249/593] Version bump to 0.8.0 and library dist --- CHANGELOG.md | 21 + bower.json | 4 +- dist/chartist.js | 1180 +++++++++++++------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 5 +- dist/chartist.min.js.map | 2 +- dist/scss/chartist.scss | 103 +- dist/scss/settings/_chartist-settings.scss | 9 +- package.json | 2 +- 9 files changed, 911 insertions(+), 417 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28560d8c..38dee11b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +v0.8.0 - 10 May 2015 +-------------------- +- Added new option to bar charts to allow a series distribution and use a simple one dimensional array for data (#209) +- Added option for label placement and refactored label positioning code (#302) +- Added option to only use integer numbers in linear scale axis (#77) +- Added possibility to add series configuration on line chart to override specific options on series level (#289, #168) +- Added functionality to handle holes in line charts (#294) +- Added step interpolation for line charts +- Added default styles for bar and horizontal bar labels that make more sense (#303) +- Added series data and meta information to events (#293) +- Changed line chart behavior to draw points from interpolated values (#295) +- Removed restriction to SVGElements so Chartist.Svg can be used for HTML DOM elements (#261) +- Refactored and simplified axis creation, also includes updated CSS label handling +- Refactored getDataArray for simplification and fixed type conversion issue with data arrays for pie charts +- Centralized high/low calculations in getHighLow() method and added support for empty charts. Thanks @scthi ! +- Fixed bug in pie chart where meta was only added when series name was specified +- Fixed bug where special condition to check single value should also include object value notation (#265) +- Fixed bug with Chartist.extend when null property is extended +- Fixed bug with Firefox dying with a DOM exception when calling getBBox() on an invisible node. Thanks @scthi ! +- Switched from object literal accessor definition to regular function (#278) + v0.7.4 - 19 Apr 2015 -------------------- - Enhanced documentation site (Accessibility plugin, live example eval, fixed path to Sass settings, better HTML example of how to include Chartist, example how to include multiple charts on one page) diff --git a/bower.json b/bower.json index 639ed559..3c8cd0ec 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.7.4", + "version": "0.8.0", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" @@ -30,6 +30,6 @@ "test" ], "resolutions": { - "chartist": "~0.7.3" + "chartist": "~0.8.0" } } diff --git a/dist/chartist.js b/dist/chartist.js index bf2f10ee..fd6823cc 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.7.4 +/* Chartist.js 0.8.0 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.7.4' + version: '0.8.0' }; (function (window, document, Chartist) { @@ -68,7 +68,7 @@ var Chartist = { var sources = Array.prototype.slice.call(arguments, 1); sources.forEach(function(source) { for (var prop in source) { - if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) { + if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) { target[prop] = Chartist.extend({}, target[prop], source[prop]); } else { target[prop] = source[prop]; @@ -314,7 +314,7 @@ var Chartist = { for (var i = 0; i < data.series.length; i++) { if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { data.series[i].data.reverse(); - } else { + } else if(data.series[i] instanceof Array) { data.series[i].reverse(); } } @@ -329,10 +329,6 @@ var Chartist = { * @return {Array} A plain array that contains the data to be visualized in the chart */ Chartist.getDataArray = function (data, reverse) { - var array = [], - value, - localData; - // If the data should be reversed but isn't we need to reverse it // If it's reversed but it shouldn't we need to reverse it back // That's required to handle data updates correctly and to reflect the responsive configurations @@ -341,27 +337,21 @@ var Chartist = { data.reversed = !data.reversed; } - for (var i = 0; i < data.series.length; i++) { - // If the series array contains an object with a data property we will use the property - // otherwise the value directly (array or number). - // We create a copy of the original data array with Array.prototype.push.apply - localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i]; - if(localData instanceof Array) { - array[i] = []; - Array.prototype.push.apply(array[i], localData); + // Rcursively walks through nested arrays and convert string values to numbers and objects with value properties + // to values. Check the tests in data core -> data normalization for a detailed specification of expected values + function recursiveConvert(value) { + if(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) { + return undefined; + } else if((value.data || value) instanceof Array) { + return (value.data || value).map(recursiveConvert); + } else if(value.hasOwnProperty('value')) { + return recursiveConvert(value.value); } else { - array[i] = localData; - } - - // Convert object values to numbers - for (var j = 0; j < array[i].length; j++) { - value = array[i][j]; - value = value.value === 0 ? 0 : (value.value || value); - array[i][j] = +value; + return +value; } } - return array; + return data.series.map(recursiveConvert); }; /** @@ -403,7 +393,7 @@ var Chartist = { } for (var j = dataArray[i].length; j < length; j++) { - dataArray[i][j] = 0; + dataArray[i][j] = undefined; } } @@ -456,31 +446,83 @@ var Chartist = { * * @memberof Chartist.Core * @param {Array} dataArray The array that contains the data to be visualized in the chart + * @param {Object} options The Object that contains all the optional values for the chart * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ - Chartist.getHighLow = function (dataArray) { + Chartist.getHighLow = function (dataArray, options) { var i, j, highLow = { - high: -Number.MAX_VALUE, - low: Number.MAX_VALUE - }; + high: options.high === undefined ? -Number.MAX_VALUE : +options.high, + low: options.low === undefined ? Number.MAX_VALUE : +options.low + }, + findHigh = options.high === undefined, + findLow = options.low === undefined; for (i = 0; i < dataArray.length; i++) { for (j = 0; j < dataArray[i].length; j++) { - if (dataArray[i][j] > highLow.high) { + if (findHigh && dataArray[i][j] > highLow.high) { highLow.high = dataArray[i][j]; } - if (dataArray[i][j] < highLow.low) { + if (findLow && dataArray[i][j] < highLow.low) { highLow.low = dataArray[i][j]; } } } + // If high and low are the same because of misconfiguration or flat data (only the same value) we need + // to set the high or low to 0 depending on the polarity + if (highLow.high <= highLow.low) { + // If both values are 0 we set high to 1 + if (highLow.low === 0) { + highLow.high = 1; + } else if (highLow.low < 0) { + // If we have the same negative value for the bounds we set bounds.high to 0 + highLow.high = 0; + } else { + // If we have the same positive value for the bounds we set bounds.low to 0 + highLow.low = 0; + } + } + return highLow; }; + /** + * 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. + * + * @memberof Chartist.Core + * @param {Number} num An integer number where the smallest factor should be searched for + * @returns {Number} The smallest integer factor of the parameter num. + */ + Chartist.rho = function(num) { + function gcd(p, q) { + if (p % q === 0) { + return q; + } else { + return gcd(q, p % q); + } + } + + function f(x) { + return x * x + 1; + } + + var x1 = 2, x2 = 2, divisor; + if (num % 2 === 0) { + return 2; + } + + do { + x1 = f(x1) % num; + x2 = f(f(x2)) % num; + divisor = gcd(Math.abs(x1 - x2), num); + } while (divisor === 1); + + return divisor; + }; + /** * Calculate and retrieve all the bounds for the chart and return them in one array * @@ -489,9 +531,10 @@ var Chartist = { * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. * @param {Number} scaleMinSpace The minimum projected length a step should result in * @param {Number} referenceValue The reference value for the chart. + * @param {Boolean} onlyInteger * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) { + Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue, onlyInteger) { var i, newMin, newMax, @@ -500,21 +543,6 @@ var Chartist = { low: highLow.low }; - // If high and low are the same because of misconfiguration or flat data (only the same value) we need - // to set the high or low to 0 depending on the polarity - if(bounds.high === bounds.low) { - // If both values are 0 we set high to 1 - if(bounds.low === 0) { - bounds.high = 1; - } else if(bounds.low < 0) { - // If we have the same negative value for the bounds we set bounds.high to 0 - bounds.high = 0; - } else { - // If we have the same positive value for the bounds we set bounds.low to 0 - bounds.low = 0; - } - } - // Overrides of high / low based on reference value, it will make sure that the invisible reference value is // used to generate the chart. This is useful when the chart always needs to contain the position of the // invisible reference value in the view i.e. for bipolar scales. @@ -525,38 +553,51 @@ var Chartist = { bounds.valueRange = bounds.high - bounds.low; bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); - bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom); - bounds.range = bounds.max - bounds.min; bounds.step = Math.pow(10, bounds.oom); + bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step; + bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step; + bounds.range = bounds.max - bounds.min; bounds.numberOfSteps = Math.round(bounds.range / bounds.step); // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace // If we are already below the scaleMinSpace value we will scale up - var length = Chartist.projectLength(axisLength, bounds.step, bounds), - scaleUp = length < scaleMinSpace; - - while (true) { - if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { - bounds.step *= 2; - } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { - bounds.step /= 2; - } else { - break; + var length = Chartist.projectLength(axisLength, bounds.step, bounds); + var scaleUp = length < scaleMinSpace; + var smallestFactor = onlyInteger ? Chartist.rho(bounds.range) : 0; + + // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1 + if(onlyInteger && Chartist.projectLength(axisLength, 1, bounds) >= scaleMinSpace) { + bounds.step = 1; + } else if(onlyInteger && smallestFactor < bounds.step && Chartist.projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) { + // If step 1 was too small, we can try the smallest factor of range + // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor + // is larger than the scaleMinSpace we should go for it. + bounds.step = smallestFactor; + } else { + // Trying to divide or multiply by 2 and find the best step value + while (true) { + if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { + bounds.step /= 2; + if(onlyInteger && bounds.step % 1 !== 0) { + bounds.step *= 2; + break; + } + } else { + break; + } } } // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - if (i + bounds.step < bounds.low) { - newMin += bounds.step; - } - - if (i - bounds.step >= bounds.high) { - newMax -= bounds.step; - } + while(newMin + bounds.step <= bounds.low) { + newMin += bounds.step; + } + while(newMax - bounds.step >= bounds.high) { + newMax -= bounds.step; } bounds.min = newMin; bounds.max = newMax; @@ -599,17 +640,20 @@ var Chartist = { * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ Chartist.createChartRect = function (svg, options, fallbackPadding) { - var yOffset = options.axisY ? options.axisY.offset || 0 : 0, - xOffset = options.axisX ? options.axisX.offset || 0 : 0, - w = Chartist.stripUnit(options.width) || svg.width(), - h = Chartist.stripUnit(options.height) || svg.height(), - normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); - - return { - x1: normalizedPadding.left + yOffset, - y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom), - x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset), - y2: normalizedPadding.top, + var hasAxis = !!(options.axisX || options.axisY); + var yAxisOffset = hasAxis ? options.axisY.offset : 0; + var xAxisOffset = hasAxis ? options.axisX.offset : 0; + // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 + var width = svg.width() || Chartist.stripUnit(options.width) || 0; + var height = svg.height() || Chartist.stripUnit(options.height) || 0; + var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); + + // If settings were to small to cope with offset (legacy) and padding, we'll adjust + width = Math.max(width, xAxisOffset + normalizedPadding.left + normalizedPadding.right); + height = Math.max(height, yAxisOffset + normalizedPadding.top + normalizedPadding.bottom); + + var chartRect = { + padding: normalizedPadding, width: function () { return this.x2 - this.x1; }, @@ -617,6 +661,31 @@ var Chartist = { return this.y1 - this.y2; } }; + + if(hasAxis) { + if (options.axisX.position === 'start') { + chartRect.y2 = normalizedPadding.top + xAxisOffset; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } else { + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1); + } + + if (options.axisY.position === 'start') { + chartRect.x1 = normalizedPadding.left + yAxisOffset; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1); + } + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } + + return chartRect; }; /** @@ -669,15 +738,22 @@ var Chartist = { * @param eventEmitter */ Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { - var labelElement, - positionalData = {}; + var labelElement; + var positionalData = {}; + positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; positionalData[axis.units.len] = projectedValue.len; - positionalData[axis.counterUnits.len] = axisOffset; + positionalData[axis.counterUnits.len] = axisOffset - 10; if(useForeignObject) { - var content = '' + labels[index] + ''; + // 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] + ''; + labelElement = group.foreignObject(content, Chartist.extend({ style: 'overflow: visible;' }, positionalData)); @@ -709,16 +785,47 @@ var Chartist = { * @param eventEmitter */ Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { - var axisOptions = options['axis' + axis.units.pos.toUpperCase()], - projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform), - labelValues = data.map(axisOptions.labelInterpolationFnc); + var axisOptions = options['axis' + axis.units.pos.toUpperCase()]; + var projectedValues = data.map(axis.projectValue.bind(axis)); + var labelValues = data.map(axisOptions.labelInterpolationFnc); projectedValues.forEach(function(projectedValue, index) { + var labelOffset = { + x: 0, + y: 0 + }; + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) if(!labelValues[index] && labelValues[index] !== 0) { return; } + // Transform to global coordinates using the chartRect + // We also need to set the label offset for the createLabel function + if(axis.units.pos === 'x') { + projectedValue.pos = chartRect.x1 + projectedValue.pos; + labelOffset.x = options.axisX.labelOffset.x; + + // If the labels should be positioned in start position (top side for vertical axis) we need to set a + // different offset as for positioned with end (bottom) + if(options.axisX.position === 'start') { + labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } else { + labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } + } else { + projectedValue.pos = chartRect.y1 - projectedValue.pos; + labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 0); + + // If the labels should be positioned in start position (left side for horizontal axis) we need to set a + // different offset as for positioned with end (right side) + if(options.axisY.position === 'start') { + labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10; + } else { + labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10; + } + } + if(axisOptions.showGrid) { Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ options.classNames.grid, @@ -727,14 +834,33 @@ var Chartist = { } if(axisOptions.showLabel) { - Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [ + Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [ options.classNames.label, - options.classNames[axis.units.dir] + options.classNames[axis.units.dir], + options.classNames[axisOptions.position] ], useForeignObject, eventEmitter); } }); }; + /** + * Helper to read series specific options from options object. It automatically falls back to the global option if + * there is no option in the series options. + * + * @param {Object} series Series object + * @param {Object} options Chartist options object + * @param {string} key The options key that should be used to obtain the options + * @returns {*} + */ + Chartist.getSeriesOption = function(series, options, key) { + if(series.name && options.series && options.series[series.name]) { + var seriesOptions = options.series[series.name]; + return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key]; + } else { + return options[key]; + } + }; + /** * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches * @@ -791,10 +917,10 @@ var Chartist = { updateCurrentOptions(true); return { - get currentOptions() { + removeMediaQueryListeners: removeMediaQueryListeners, + getCurrentOptions: function getCurrentOptions() { return Chartist.extend({}, currentOptions); - }, - removeMediaQueryListeners: removeMediaQueryListeners + } }; }; @@ -817,11 +943,27 @@ var Chartist = { * @return {Function} */ Chartist.Interpolation.none = function() { - return function cardinal(pathCoordinates) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + return function none(pathCoordinates, valueData) { + var path = new Chartist.Svg.Path(); + // We need to assume that the first value is a "hole" + var hole = true; + + for(var i = 1; i < pathCoordinates.length; i += 2) { + var data = valueData[(i - 1) / 2]; - for(var i = 3; i < pathCoordinates.length; i += 2) { - path.line(pathCoordinates[i - 1], pathCoordinates[i]); + // If the current value is undefined we should treat it as a hole start + if(data.value === undefined) { + hole = true; + } else { + // If this value is valid we need to check if we're coming out of a hole + if(hole) { + // If we are coming out of a hole we should first make a move and also reset the hole flag + path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data); + hole = false; + } else { + path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data); + } + } } return path; @@ -858,24 +1000,42 @@ var Chartist = { var d = 1 / Math.max(1, options.divisor); - return function simple(pathCoordinates) { - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]); + return function simple(pathCoordinates, valueData) { + var path = new Chartist.Svg.Path(); + var hole = true; for(var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2], - prevY = pathCoordinates[i - 1], - currX = pathCoordinates[i], - currY = pathCoordinates[i + 1], - length = (currX - prevX) * d; - - path.curve( - prevX + length, - prevY, - currX - length, - currY, - currX, - currY - ); + var prevX = pathCoordinates[i - 2]; + var prevY = pathCoordinates[i - 1]; + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var length = (currX - prevX) * d; + var prevData = valueData[(i / 2) - 1]; + var currData = valueData[i / 2]; + + if(prevData.value === undefined) { + hole = true; + } else { + + if(hole) { + path.move(prevX, prevY, false, prevData); + } + + if(currData.value !== undefined) { + path.curve( + prevX + length, + prevY, + currX - length, + currY, + currX, + currY, + false, + currData + ); + + hole = false; + } + } } return path; @@ -913,47 +1073,169 @@ var Chartist = { var t = Math.min(1, Math.max(0, options.tension)), c = 1 - t; - return function cardinal(pathCoordinates) { - // If less than two points we need to fallback to no smoothing - if(pathCoordinates.length <= 4) { - return Chartist.Interpolation.none()(pathCoordinates); + // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates + // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards. + // This functionality is necessary to treat "holes" in the line charts + function splitIntoSegments(pathCoordinates, valueData) { + var segments = []; + var hole = true; + + for(var i = 0; i < pathCoordinates.length; i += 2) { + // If this value is a "hole" we set the hole flag + if(valueData[i / 2].value === undefined) { + hole = true; + } else { + // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment + if(hole) { + segments.push({ + pathCoordinates: [], + valueData: [] + }); + // As we have a valid value now, we are not in a "hole" anymore + hole = false; + } + + // Add to the segment pathCoordinates and valueData + segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); + segments[segments.length - 1].valueData.push(valueData[i / 2]); + } } - var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]), - z; - - for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { - var p = [ - {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, - {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, - {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, - {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} - ]; - if (z) { - if (!i) { - p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; - } else if (iLen - 4 === i) { - p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; - } else if (iLen - 2 === i) { - p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; - p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; + return segments; + } + + return function cardinal(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = splitIntoSegments(pathCoordinates, valueData); + + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + if(segments.length > 1) { + var paths = []; + // For each segment we will recurse the cardinal function + segments.forEach(function(segment) { + paths.push(cardinal(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return Chartist.Svg.Path.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; + + // If less than two points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return Chartist.Interpolation.none()(pathCoordinates, valueData); + } + + var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), + z; + + for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, + {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, + {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, + {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; + } else if (iLen - 4 === i) { + p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + } else if (iLen - 2 === i) { + p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; + } } + + path.curve( + (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), + (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), + (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), + (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), + p[2].x, + p[2].y, + false, + valueData[(i + 2) / 2] + ); + } + + return path; + } + }; + }; + + /** + * 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. + * + * 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`. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.step({ + * postpone: true + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param options + * @returns {Function} + */ + Chartist.Interpolation.step = function(options) { + var defaultOptions = { + postpone: true + }; + + options = Chartist.extend({}, defaultOptions, options); + + return function step(pathCoordinates, valueData) { + var path = new Chartist.Svg.Path(); + var hole = true; + + for (var i = 2; i < pathCoordinates.length; i += 2) { + var prevX = pathCoordinates[i - 2]; + var prevY = pathCoordinates[i - 1]; + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var prevData = valueData[(i / 2) - 1]; + var currData = valueData[i / 2]; + + // If last point is a "hole" + if(prevData.value === undefined) { + hole = true; } else { - if (iLen - 4 === i) { - p[3] = p[2]; - } else if (!i) { - p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; + // If last point is not a "hole" but we just came back out of a "hole" we need to move first + if(hole) { + path.move(prevX, prevY, false, prevData); } - } - path.curve( - (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), - (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), - (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), - (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), - p[2].x, - p[2].y - ); + // If the current point is also not a hole we can draw the step lines + if(currData.value !== undefined) { + if(options.postpone) { + // If postponed we should draw the step line with the value of the previous value + path.line(currX, prevY, false, prevData); + } else { + // If not postponed we should draw the step line with the value of the current value + path.line(prevX, currY, false, currData); + } + // Line to the actual point (this should only be a Y-Axis movement + path.line(currX, currY, false, currData); + // Reset the "hole" flag as previous and current point have valid values + hole = false; + } + } } return path; @@ -1196,7 +1478,7 @@ var Chartist = { // Only re-created the chart if it has been initialized yet if(!this.initializeTimeoutId) { - this.createChart(this.optionsProvider.currentOptions); + this.createChart(this.optionsProvider.getCurrentOptions()); } // Return a reference to the chart object to chain up calls @@ -1269,7 +1551,7 @@ var Chartist = { }); // Create the first chart - this.createChart(this.optionsProvider.currentOptions); + this.createChart(this.optionsProvider.getCurrentOptions()); // As chart is initialized from the event loop now we can reset our timeout reference // This is important if the chart gets initialized on the same element twice @@ -1363,7 +1645,7 @@ var Chartist = { * * @memberof Chartist.Svg * @constructor - * @param {String|SVGElement} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg + * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg * @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. * @param {String} className This class or class list will be added to the SVG element * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child @@ -1371,7 +1653,7 @@ var Chartist = { */ function Svg(name, attributes, className, parent, insertFirst) { // If Svg is getting called with an SVG element we just return the wrapper - if(name instanceof SVGElement) { + if(name instanceof Element) { this._node = name; } else { this._node = document.createElementNS(svgNs, name); @@ -1449,6 +1731,7 @@ var Chartist = { /** * Returns the parent Chartist.SVG wrapper object * + * @memberof Chartist.Svg * @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. */ function parent() { @@ -1458,6 +1741,7 @@ var Chartist = { /** * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. * + * @memberof Chartist.Svg * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element */ function root() { @@ -1471,6 +1755,7 @@ var Chartist = { /** * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. * + * @memberof Chartist.Svg * @param {String} selector A CSS selector that is used to query for child SVG elements * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found */ @@ -1482,6 +1767,7 @@ var Chartist = { /** * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. * + * @memberof Chartist.Svg * @param {String} selector A CSS selector that is used to query for child SVG elements * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found */ @@ -1647,6 +1933,24 @@ var Chartist = { return this; } + /** + * "Save" way to get property value from svg BoundingBox. + * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node. + * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/) + * + * @memberof Chartist.Svg + * @param {SVGElement} node The svg node to + * @param {String} prop The property to fetch (ex.: height, width, ...) + * @returns {Number} The value of the given bbox property + */ + function getBBoxProperty(node, prop) { + try { + return node.getBBox()[prop]; + } catch(e) {} + + return 0; + } + /** * Get element height with fallback to svg BoundingBox or parent container dimensions: * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) @@ -1655,7 +1959,7 @@ var Chartist = { * @return {Number} The elements height in pixels */ function height() { - return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight; + return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight; } /** @@ -1666,7 +1970,7 @@ var Chartist = { * @return {Number} The elements width in pixels */ function width() { - return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth; + return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth; } /** @@ -1964,10 +2268,12 @@ var Chartist = { accuracy: 3 }; - function element(command, params, pathElements, pos, relative) { - pathElements.splice(pos, 0, Chartist.extend({ + function element(command, params, pathElements, pos, relative, data) { + var pathElement = Chartist.extend({ command: relative ? command.toLowerCase() : command.toUpperCase() - }, params)); + }, params, data ? { data: data } : {} ); + + pathElements.splice(pos, 0, pathElement); } function forEachParam(pathElements, cb) { @@ -2028,13 +2334,14 @@ var Chartist = { * @param {Number} x The x coordinate for the move element. * @param {Number} y The y coordinate for the move element. * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function move(x, y, relative) { + function move(x, y, relative, data) { element('M', { x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } @@ -2045,13 +2352,14 @@ var Chartist = { * @param {Number} x The x coordinate for the line element. * @param {Number} y The y coordinate for the line element. * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function line(x, y, relative) { + function line(x, y, relative, data) { element('L', { x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } @@ -2066,9 +2374,10 @@ var Chartist = { * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function curve(x1, y1, x2, y2, x, y, relative) { + function curve(x1, y1, x2, y2, x, y, relative, data) { element('C', { x1: +x1, y1: +y1, @@ -2076,7 +2385,7 @@ var Chartist = { y2: +y2, x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } @@ -2092,9 +2401,10 @@ var Chartist = { * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ - function arc(rx, ry, xAr, lAf, sf, x, y, relative) { + function arc(rx, ry, xAr, lAf, sf, x, y, relative, data) { element('A', { rx: +rx, ry: +ry, @@ -2103,7 +2413,7 @@ var Chartist = { sf: +sf, x: +x, y: +y - }, this.pathElements, this.pos++, relative); + }, this.pathElements, this.pos++, relative, data); return this; } @@ -2245,6 +2555,27 @@ var Chartist = { return c; } + /** + * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths. + * + * @memberof Chartist.Svg.Path + * @param {Array} paths A list of paths to be joined together. The order is important. + * @param {boolean} close If the newly created path should be a closed path + * @param {Object} options Path options for the newly created path. + * @return {Chartist.Svg.Path} + */ + + function join(paths, close, options) { + var joinedPath = new Chartist.Svg.Path(close, options); + for(var i = 0; i < paths.length; i++) { + var path = paths[i]; + for(var j = 0; j < path.pathElements.length; j++) { + joinedPath.pathElements.push(path.pathElements[j]); + } + } + return joinedPath; + } + Chartist.Svg.Path = Chartist.Class.extend({ constructor: SvgPath, position: position, @@ -2262,6 +2593,7 @@ var Chartist = { }); Chartist.Svg.Path.elementDescriptions = elementDescriptions; + Chartist.Svg.Path.join = join; }(window, document, Chartist)); ;/** * Axis base class used to implement different axis types @@ -2291,14 +2623,12 @@ var Chartist = { } }; - function Axis(units, chartRect, transform, labelOffset, options) { + function Axis(units, chartRect, options) { this.units = units; this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; this.chartRect = chartRect; this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; this.gridOffset = chartRect[units.rectOffset]; - this.transform = transform; - this.labelOffset = labelOffset; this.options = options; } @@ -2321,20 +2651,18 @@ var Chartist = { (function (window, document, Chartist) { 'use strict'; - function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) { + function LinearScaleAxis(axisUnit, chartRect, options) { Chartist.LinearScaleAxis.super.constructor.call(this, axisUnit, chartRect, - transform, - labelOffset, options); - this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue); + this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger); } function projectValue(value) { return { - pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step), + pos: this.axisLength * (value - this.bounds.min) / this.bounds.range, len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) }; } @@ -2354,12 +2682,10 @@ var Chartist = { (function (window, document, Chartist) { 'use strict'; - function StepAxis(axisUnit, chartRect, transform, labelOffset, options) { + function StepAxis(axisUnit, chartRect, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, chartRect, - transform, - labelOffset, options); this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); @@ -2399,6 +2725,8 @@ var Chartist = { axisX: { // The offset of the labels to the chart area offset: 30, + // 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. + position: 'end', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, @@ -2409,12 +2737,16 @@ var Chartist = { // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label - labelInterpolationFnc: Chartist.noop + labelInterpolationFnc: Chartist.noop, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Options for Y-Axis axisY: { // The offset of the labels to the chart area offset: 40, + // 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. + position: 'start', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, @@ -2427,7 +2759,9 @@ var Chartist = { // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20 + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, @@ -2448,7 +2782,12 @@ var Chartist = { // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, // 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} - chartPadding: 5, + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, // 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. fullWidth: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. @@ -2465,7 +2804,9 @@ var Chartist = { grid: 'ct-grid', gridGroup: 'ct-grids', vertical: 'ct-vertical', - horizontal: 'ct-horizontal' + horizontal: 'ct-horizontal', + start: 'ct-start', + end: 'ct-end' } }; @@ -2474,53 +2815,25 @@ var Chartist = { * */ function createChart(options) { - var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), - normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding); + var seriesGroups = []; + var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); + var highLow = Chartist.getHighLow(normalizedData, options); - var highLow = Chartist.getHighLow(normalizedData); - // Overrides of high / low from settings - highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); - highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); - - var axisX = new Chartist.StepAxis( - Chartist.Axis.units.x, - chartRect, - function xAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, - { - stepCount: this.data.labels.length, - stretch: options.fullWidth - } - ); + var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { + stepCount: this.data.labels.length, + stretch: options.fullWidth + }); - var axisY = new Chartist.LinearScaleAxis( - Chartist.Axis.units.y, - chartRect, - function yAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) - }, - { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace - } - ); + var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace, + onlyInteger: options.axisY.onlyInteger + }); // Start drawing var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), @@ -2564,99 +2877,122 @@ var Chartist = { (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - var pathCoordinates = []; + var pathCoordinates = [], + pathData = []; normalizedData[seriesIndex].forEach(function(value, valueIndex) { var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos }; pathCoordinates.push(p.x, p.y); + pathData.push({ + value: value, + valueIndex: valueIndex, + meta: Chartist.getMetaData(series, valueIndex) + }); + }.bind(this)); + + var seriesOptions = { + lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'), + showPoint: Chartist.getSeriesOption(series, options, 'showPoint'), + showLine: Chartist.getSeriesOption(series, options, 'showLine'), + showArea: Chartist.getSeriesOption(series, options, 'showArea') + }; - //If we should show points we need to create them now to avoid secondary loop - // Small offset for Firefox to render squares correctly - if (options.showPoint) { + var smoothing = typeof seriesOptions.lineSmooth === 'function' ? + seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()); + // Interpolating path where pathData will be used to annotate each path element so we can trace back the original + // index, value and meta data + var path = smoothing(pathCoordinates, pathData); + + // If we should show points we need to create them now to avoid secondary loop + // Points are drawn from the pathElements returned by the interpolation function + // Small offset for Firefox to render squares correctly + if (seriesOptions.showPoint) { + + path.pathElements.forEach(function(pathElement) { var point = seriesGroups[seriesIndex].elem('line', { - x1: p.x, - y1: p.y, - x2: p.x + 0.01, - y2: p.y + x1: pathElement.x, + y1: pathElement.y, + x2: pathElement.x + 0.01, + y2: pathElement.y }, options.classNames.point).attr({ - 'value': value, - 'meta': Chartist.getMetaData(series, valueIndex) + 'value': pathElement.data.value, + 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'point', - value: value, - index: valueIndex, + value: pathElement.data.value, + index: pathElement.data.valueIndex, + meta: pathElement.data.meta, + series: series, + seriesIndex: seriesIndex, group: seriesGroups[seriesIndex], element: point, - x: p.x, - y: p.y + x: pathElement.x, + y: pathElement.y }); - } - }.bind(this)); + }.bind(this)); + } - // TODO: Nicer handling of conditions, maybe composition? - if (options.showLine || options.showArea) { - var smoothing = typeof options.lineSmooth === 'function' ? - options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()), - path = smoothing(pathCoordinates); - - if(options.showLine) { - var line = seriesGroups[seriesIndex].elem('path', { - d: path.stringify() - }, options.classNames.line, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); + if(seriesOptions.showLine) { + var line = seriesGroups[seriesIndex].elem('path', { + d: path.stringify() + }, options.classNames.line, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); - this.eventEmitter.emit('draw', { - type: 'line', - values: normalizedData[seriesIndex], - path: path.clone(), - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: line - }); - } + this.eventEmitter.emit('draw', { + type: 'line', + values: normalizedData[seriesIndex], + path: path.clone(), + chartRect: chartRect, + index: seriesIndex, + series: series, + seriesIndex: seriesIndex, + group: seriesGroups[seriesIndex], + element: line + }); + } - if(options.showArea) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); - - // We project the areaBase value into screen coordinates - var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; - - // Clone original path and splice our new area path to add the missing path elements to close the area shape - var areaPath = path.clone(); - // Modify line path and add missing elements for area - areaPath.position(0) - .remove(1) - .move(chartRect.x1, areaBaseProjected) - .line(pathCoordinates[0], pathCoordinates[1]) - .position(areaPath.pathElements.length) - .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); - - // Create the new path for the area shape with the area class from the options - var area = seriesGroups[seriesIndex].elem('path', { - d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); + if(seriesOptions.showArea) { + // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; + + // Clone original path and splice our new area path to add the missing path elements to close the area shape + var areaPath = path.clone(); + // Modify line path and add missing elements for area + areaPath.position(0) + .remove(1) + .move(chartRect.x1, areaBaseProjected) + .line(pathCoordinates[0], pathCoordinates[1]) + .position(areaPath.pathElements.length) + .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); + + // Create the new path for the area shape with the area class from the options + var area = seriesGroups[seriesIndex].elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); - this.eventEmitter.emit('draw', { - type: 'area', - values: normalizedData[seriesIndex], - path: areaPath.clone(), - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: area - }); - } + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[seriesIndex], + path: areaPath.clone(), + series: series, + seriesIndex: seriesIndex, + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], + element: area + }); } }.bind(this)); @@ -2786,6 +3122,8 @@ var Chartist = { axisX: { // The offset of the chart drawing area to the border of the container offset: 30, + // 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. + position: 'end', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, @@ -2798,12 +3136,16 @@ var Chartist = { // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum width in pixel of the scale steps - scaleMinSpace: 40 + scaleMinSpace: 30, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Options for Y-Axis axisY: { // The offset of the chart drawing area to the border of the container offset: 40, + // 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. + position: 'start', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, @@ -2816,7 +3158,9 @@ var Chartist = { // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20 + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false }, // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, @@ -2826,19 +3170,29 @@ var Chartist = { high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false, // 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} - chartPadding: 5, + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, // If set to true this property will cause the series bars to be stacked and 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. stackBars: false, // 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. horizontalBars: false, + // 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. + distributeSeries: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. reverseData: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', + horizontalBars: 'ct-horizontal-bars', label: 'ct-label', labelGroup: 'ct-labels', series: 'ct-series', @@ -2846,7 +3200,9 @@ var Chartist = { grid: 'ct-grid', gridGroup: 'ct-grids', vertical: 'ct-vertical', - horizontal: 'ct-horizontal' + horizontal: 'ct-horizontal', + start: 'ct-start', + end: 'ct-end' } }; @@ -2855,13 +3211,20 @@ var Chartist = { * */ function createChart(options) { - var seriesGroups = [], - normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length), - normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding), - highLow; + var seriesGroups = []; + var data = Chartist.getDataArray(this.data, options.reverseData); + var normalizedData = options.distributeSeries ? data.map(function(value) { + return [value]; + }) : Chartist.normalizeDataArray(data, this.data.labels.length); + var highLow; // Create new svg element - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + this.svg = Chartist.createSvg( + this.container, + options.width, + options.height, + options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '') + ); if(options.stackBars) { // If stacked bars we need to calculate the high low from stacked values from each series @@ -2869,9 +3232,9 @@ var Chartist = { return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); }); - highLow = Chartist.getHighLow([serialSums]); + highLow = Chartist.getHighLow([serialSums], options); } else { - highLow = Chartist.getHighLow(normalizedData); + highLow = Chartist.getHighLow(normalizedData, options); } // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); @@ -2880,79 +3243,49 @@ var Chartist = { var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, + labelAxisStepCount, labelAxis, axisX, axisY; + // We need to set step count based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we need to use the one dimensional series array + // length as step count for the label axis + labelAxisStepCount = normalizedData.length; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore set step + // count to 1 + labelAxisStepCount = 1; + } else { + // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length + // as the bars are normalized + labelAxisStepCount = this.data.labels.length; + } + + // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { - labelAxis = axisY = new Chartist.StepAxis( - Chartist.Axis.units.y, - chartRect, - function timeAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length - }, - { - stepCount: this.data.labels.length, - stretch: options.fullHeight - } - ); - - valueAxis = axisX = new Chartist.LinearScaleAxis( - Chartist.Axis.units.x, - chartRect, - function valueAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, - { - highLow: highLow, - scaleMinSpace: options.axisX.scaleMinSpace, - referenceValue: 0 - } - ); + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, { + stepCount: labelAxisStepCount + }); + + valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, { + highLow: highLow, + scaleMinSpace: options.axisX.scaleMinSpace, + onlyInteger: options.axisX.onlyInteger, + referenceValue: 0 + }); } else { - labelAxis = axisX = new Chartist.StepAxis( - Chartist.Axis.units.x, - chartRect, - function timeAxisTransform(projectedValue) { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - return projectedValue; - }, - { - x: options.axisX.labelOffset.x, - y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20) - }, - { - stepCount: this.data.labels.length - } - ); - - valueAxis = axisY = new Chartist.LinearScaleAxis( - Chartist.Axis.units.y, - chartRect, - function valueAxisTransform(projectedValue) { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - return projectedValue; - }, - { - x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0), - y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0) - }, - { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - referenceValue: 0 - } - ); + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { + stepCount: labelAxisStepCount + }); + + valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { + highLow: highLow, + scaleMinSpace: options.axisY.scaleMinSpace, + onlyInteger: options.axisY.onlyInteger, + referenceValue: 0 + }); } // Start drawing @@ -2990,7 +3323,21 @@ var Chartist = { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. var biPol = seriesIndex - (this.data.series.length - 1) / 2, // Half of the period width between vertical grid lines used to position bars - periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2; + periodHalfLength; + + // We need to set periodHalfLength based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array + // which is the series count and divide by 2 + periodHalfLength = labelAxis.axisLength / normalizedData.length / 2; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis + // length by 2 + periodHalfLength = labelAxis.axisLength / 2; + } else { + // On regular bar charts we should just use the series length + periodHalfLength = labelAxis.axisLength / normalizedData[seriesIndex].length / 2; + } seriesGroups[seriesIndex] = this.svg.elem('g'); @@ -3007,17 +3354,42 @@ var Chartist = { ].join(' ')); normalizedData[seriesIndex].forEach(function(value, valueIndex) { - var projected = { - x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos - }, + var projected, bar, - previousStack; + previousStack, + labelAxisValueIndex; + + // We need to set labelAxisValueIndex based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection + // on the step axis for label positioning + labelAxisValueIndex = seriesIndex; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use + // 0 for projection on the label step axis + labelAxisValueIndex = 0; + } else { + // On regular bar charts we just use the value index to project on the label step axis + labelAxisValueIndex = valueIndex; + } + + // We need to transform coordinates differently based on the chart layout + if(options.horizontalBars) { + projected = { + x: chartRect.x1 + valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos + }; + } else { + projected = { + x: chartRect.x1 + labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + } + } // Offset to center bar between grid lines projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); - // Using bi-polar offset for multiple series if no stacked bars are used - projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + // Using bi-polar offset for multiple series if no stacked bars or series distribution is used + projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); // Enter value in stacked bar values used to remember previous screen value for stacking up bars previousStack = stackedBarValues[valueIndex] || zeroPoint; @@ -3039,6 +3411,9 @@ var Chartist = { type: 'bar', value: value, index: valueIndex, + meta: Chartist.getMetaData(series, valueIndex), + series: series, + seriesIndex: seriesIndex, chartRect: chartRect, group: seriesGroups[seriesIndex], element: bar @@ -3130,7 +3505,7 @@ var Chartist = { height: undefined, // 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} chartPadding: 5, - // Override the class names that get used to generate the SVG structure of the chart + // Override the class names that are used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-pie', series: 'ct-series', @@ -3224,26 +3599,24 @@ var Chartist = { // Check if there is only one non-zero value in the series array. var hasSingleValInSeries = this.data.series.filter(function(val) { - return val !== 0; + return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { + var series = this.data.series[i]; seriesGroups[i] = this.svg.elem('g', null, null, true); - // If the series is an object and contains a name we add a custom attribute - if(this.data.series[i].name) { - seriesGroups[i].attr({ - 'series-name': this.data.series[i].name, - 'meta': Chartist.serialize(this.data.series[i].meta) - }, Chartist.xmlNs.uri); - } + // If the series is an object and contains a name or meta data we add a custom attribute + seriesGroups[i].attr({ + 'series-name': series.name + }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ options.classNames.series, - (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) ].join(' ')); var endAngle = startAngle + dataArray[i] / totalDataSum * 360; @@ -3274,7 +3647,8 @@ var Chartist = { // Adding the pie series value to the path pathElement.attr({ - 'value': dataArray[i] + 'value': dataArray[i], + 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // If this is a donut, we add the stroke-width as style attribute @@ -3290,6 +3664,8 @@ var Chartist = { value: dataArray[i], totalDataSum: totalDataSum, index: i, + meta: series.meta, + series: series, group: seriesGroups[i], element: pathElement, path: path.clone(), @@ -3340,7 +3716,7 @@ var Chartist = { * * @memberof Chartist.Pie * @param {String|Node} query A selector query string or directly a DOM element - * @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 objects that contain a data property with the value and a className property to override the CSS class name for the series group. + * @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. * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] * @return {Object} An object with a version and an update method to manually redraw the chart @@ -3381,17 +3757,25 @@ var Chartist = { * }); * * @example - * // Overriding the class names for individual series + * // Overriding the class names for individual series as well as a name and meta data. + * // The name will be written as ct:series-name attribute and the meta data will be serialized and written + * // to a ct:meta attribute. * new Chartist.Pie('.ct-chart', { * series: [{ - * data: 20, - * className: 'my-custom-class-one' + * value: 20, + * name: 'Series 1', + * className: 'my-custom-class-one', + * meta: 'Meta One' * }, { - * data: 10, - * className: 'my-custom-class-two' + * value: 10, + * name: 'Series 2', + * className: 'my-custom-class-two', + * meta: 'Meta Two' * }, { - * data: 70, - * className: 'my-custom-class-three' + * value: 70, + * name: 'Series 3', + * className: 'my-custom-class-three', + * meta: 'Meta Three' * }] * }); */ diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 84ff4bdc..fbf4d61c 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1 +1 @@ -.ct-chart .ct-label,.ct-chart .ct-label.ct-horizontal{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:left}.ct-chart .ct-label.ct-vertical{display:block;width:100%;height:100%;fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;text-align:right}.ct-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#f4c63d}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#f4c63d}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#d17905}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#d17905}.ct-chart .ct-series.ct-series-e .ct-bar,.ct-chart .ct-series.ct-series-e .ct-line,.ct-chart .ct-series.ct-series-e .ct-point,.ct-chart .ct-series.ct-series-e .ct-slice.ct-donut{stroke:#453d3f}.ct-chart .ct-series.ct-series-e .ct-area,.ct-chart .ct-series.ct-series-e .ct-slice:not(.ct-donut){fill:#453d3f}.ct-chart .ct-series.ct-series-f .ct-bar,.ct-chart .ct-series.ct-series-f .ct-line,.ct-chart .ct-series.ct-series-f .ct-point,.ct-chart .ct-series.ct-series-f .ct-slice.ct-donut{stroke:#59922b}.ct-chart .ct-series.ct-series-f .ct-area,.ct-chart .ct-series.ct-series-f .ct-slice:not(.ct-donut){fill:#59922b}.ct-chart .ct-series.ct-series-g .ct-bar,.ct-chart .ct-series.ct-series-g .ct-line,.ct-chart .ct-series.ct-series-g .ct-point,.ct-chart .ct-series.ct-series-g .ct-slice.ct-donut{stroke:#0544d3}.ct-chart .ct-series.ct-series-g .ct-area,.ct-chart .ct-series.ct-series-g .ct-slice:not(.ct-donut){fill:#0544d3}.ct-chart .ct-series.ct-series-h .ct-bar,.ct-chart .ct-series.ct-series-h .ct-line,.ct-chart .ct-series.ct-series-h .ct-point,.ct-chart .ct-series.ct-series-h .ct-slice.ct-donut{stroke:#6b0392}.ct-chart .ct-series.ct-series-h .ct-area,.ct-chart .ct-series.ct-series-h .ct-slice:not(.ct-donut){fill:#6b0392}.ct-chart .ct-series.ct-series-i .ct-bar,.ct-chart .ct-series.ct-series-i .ct-line,.ct-chart .ct-series.ct-series-i .ct-point,.ct-chart .ct-series.ct-series-i .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-i .ct-area,.ct-chart .ct-series.ct-series-i .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-j .ct-bar,.ct-chart .ct-series.ct-series-j .ct-line,.ct-chart .ct-series.ct-series-j .ct-point,.ct-chart .ct-series.ct-series-j .ct-slice.ct-donut{stroke:#dda458}.ct-chart .ct-series.ct-series-j .ct-area,.ct-chart .ct-series.ct-series-j .ct-slice:not(.ct-donut){fill:#dda458}.ct-chart .ct-series.ct-series-k .ct-bar,.ct-chart .ct-series.ct-series-k .ct-line,.ct-chart .ct-series.ct-series-k .ct-point,.ct-chart .ct-series.ct-series-k .ct-slice.ct-donut{stroke:#eacf7d}.ct-chart .ct-series.ct-series-k .ct-area,.ct-chart .ct-series.ct-series-k .ct-slice:not(.ct-donut){fill:#eacf7d}.ct-chart .ct-series.ct-series-l .ct-bar,.ct-chart .ct-series.ct-series-l .ct-line,.ct-chart .ct-series.ct-series-l .ct-point,.ct-chart .ct-series.ct-series-l .ct-slice.ct-donut{stroke:#86797d}.ct-chart .ct-series.ct-series-l .ct-area,.ct-chart .ct-series.ct-series-l .ct-slice:not(.ct-donut){fill:#86797d}.ct-chart .ct-series.ct-series-m .ct-bar,.ct-chart .ct-series.ct-series-m .ct-line,.ct-chart .ct-series.ct-series-m .ct-point,.ct-chart .ct-series.ct-series-m .ct-slice.ct-donut{stroke:#b2c326}.ct-chart .ct-series.ct-series-m .ct-area,.ct-chart .ct-series.ct-series-m .ct-slice:not(.ct-donut){fill:#b2c326}.ct-chart .ct-series.ct-series-n .ct-bar,.ct-chart .ct-series.ct-series-n .ct-line,.ct-chart .ct-series.ct-series-n .ct-point,.ct-chart .ct-series.ct-series-n .ct-slice.ct-donut{stroke:#6188e2}.ct-chart .ct-series.ct-series-n .ct-area,.ct-chart .ct-series.ct-series-n .ct-slice:not(.ct-donut){fill:#6188e2}.ct-chart .ct-series.ct-series-o .ct-bar,.ct-chart .ct-series.ct-series-o .ct-line,.ct-chart .ct-series.ct-series-o .ct-point,.ct-chart .ct-series.ct-series-o .ct-slice.ct-donut{stroke:#a748ca}.ct-chart .ct-series.ct-series-o .ct-area,.ct-chart .ct-series.ct-series-o .ct-slice:not(.ct-donut){fill:#a748ca}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{content:"";display:table;clear:both}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{content:"";display:table;clear:both}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{content:"";display:table;clear:both}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{content:"";display:table;clear:both}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{content:"";display:table;clear:both}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{content:"";display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{content:"";display:table;clear:both}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{content:"";display:table;clear:both}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{content:"";display:table;clear:both}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{content:"";display:table;clear:both}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file +.ct-chart.ct-double-octave:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-second:after,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-third:after,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-third:after,.ct-chart.ct-octave:after,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-square:after{content:"";clear:both}.ct-chart.ct-double-octave:after,.ct-chart.ct-double-octave:before,.ct-chart.ct-golden-section:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-eleventh:before,.ct-chart.ct-major-second:after,.ct-chart.ct-major-second:before,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-seventh:before,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-sixth:before,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-tenth:before,.ct-chart.ct-major-third:after,.ct-chart.ct-major-third:before,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-major-twelfth:before,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-second:before,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-seventh:before,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-sixth:before,.ct-chart.ct-minor-third:after,.ct-chart.ct-minor-third:before,.ct-chart.ct-octave:after,.ct-chart.ct-octave:before,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fifth:before,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-perfect-fourth:before,.ct-chart.ct-square:after,.ct-chart.ct-square:before{content:""}.ct-chart .ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart .ct-chart-bar .ct-label,.ct-chart .ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart .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 .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 .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-chart .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 .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 .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 .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 .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 .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 .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-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#f4c63d}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#f4c63d}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#d17905}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#d17905}.ct-chart .ct-series.ct-series-e .ct-bar,.ct-chart .ct-series.ct-series-e .ct-line,.ct-chart .ct-series.ct-series-e .ct-point,.ct-chart .ct-series.ct-series-e .ct-slice.ct-donut{stroke:#453d3f}.ct-chart .ct-series.ct-series-e .ct-area,.ct-chart .ct-series.ct-series-e .ct-slice:not(.ct-donut){fill:#453d3f}.ct-chart .ct-series.ct-series-f .ct-bar,.ct-chart .ct-series.ct-series-f .ct-line,.ct-chart .ct-series.ct-series-f .ct-point,.ct-chart .ct-series.ct-series-f .ct-slice.ct-donut{stroke:#59922b}.ct-chart .ct-series.ct-series-f .ct-area,.ct-chart .ct-series.ct-series-f .ct-slice:not(.ct-donut){fill:#59922b}.ct-chart .ct-series.ct-series-g .ct-bar,.ct-chart .ct-series.ct-series-g .ct-line,.ct-chart .ct-series.ct-series-g .ct-point,.ct-chart .ct-series.ct-series-g .ct-slice.ct-donut{stroke:#0544d3}.ct-chart .ct-series.ct-series-g .ct-area,.ct-chart .ct-series.ct-series-g .ct-slice:not(.ct-donut){fill:#0544d3}.ct-chart .ct-series.ct-series-h .ct-bar,.ct-chart .ct-series.ct-series-h .ct-line,.ct-chart .ct-series.ct-series-h .ct-point,.ct-chart .ct-series.ct-series-h .ct-slice.ct-donut{stroke:#6b0392}.ct-chart .ct-series.ct-series-h .ct-area,.ct-chart .ct-series.ct-series-h .ct-slice:not(.ct-donut){fill:#6b0392}.ct-chart .ct-series.ct-series-i .ct-bar,.ct-chart .ct-series.ct-series-i .ct-line,.ct-chart .ct-series.ct-series-i .ct-point,.ct-chart .ct-series.ct-series-i .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-i .ct-area,.ct-chart .ct-series.ct-series-i .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-j .ct-bar,.ct-chart .ct-series.ct-series-j .ct-line,.ct-chart .ct-series.ct-series-j .ct-point,.ct-chart .ct-series.ct-series-j .ct-slice.ct-donut{stroke:#dda458}.ct-chart .ct-series.ct-series-j .ct-area,.ct-chart .ct-series.ct-series-j .ct-slice:not(.ct-donut){fill:#dda458}.ct-chart .ct-series.ct-series-k .ct-bar,.ct-chart .ct-series.ct-series-k .ct-line,.ct-chart .ct-series.ct-series-k .ct-point,.ct-chart .ct-series.ct-series-k .ct-slice.ct-donut{stroke:#eacf7d}.ct-chart .ct-series.ct-series-k .ct-area,.ct-chart .ct-series.ct-series-k .ct-slice:not(.ct-donut){fill:#eacf7d}.ct-chart .ct-series.ct-series-l .ct-bar,.ct-chart .ct-series.ct-series-l .ct-line,.ct-chart .ct-series.ct-series-l .ct-point,.ct-chart .ct-series.ct-series-l .ct-slice.ct-donut{stroke:#86797d}.ct-chart .ct-series.ct-series-l .ct-area,.ct-chart .ct-series.ct-series-l .ct-slice:not(.ct-donut){fill:#86797d}.ct-chart .ct-series.ct-series-m .ct-bar,.ct-chart .ct-series.ct-series-m .ct-line,.ct-chart .ct-series.ct-series-m .ct-point,.ct-chart .ct-series.ct-series-m .ct-slice.ct-donut{stroke:#b2c326}.ct-chart .ct-series.ct-series-m .ct-area,.ct-chart .ct-series.ct-series-m .ct-slice:not(.ct-donut){fill:#b2c326}.ct-chart .ct-series.ct-series-n .ct-bar,.ct-chart .ct-series.ct-series-n .ct-line,.ct-chart .ct-series.ct-series-n .ct-point,.ct-chart .ct-series.ct-series-n .ct-slice.ct-donut{stroke:#6188e2}.ct-chart .ct-series.ct-series-n .ct-area,.ct-chart .ct-series.ct-series-n .ct-slice:not(.ct-donut){fill:#6188e2}.ct-chart .ct-series.ct-series-o .ct-bar,.ct-chart .ct-series.ct-series-o .ct-line,.ct-chart .ct-series.ct-series-o .ct-point,.ct-chart .ct-series.ct-series-o .ct-slice.ct-donut{stroke:#a748ca}.ct-chart .ct-series.ct-series-o .ct-area,.ct-chart .ct-series.ct-series-o .ct-slice:not(.ct-donut){fill:#a748ca}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{display:table}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{display:table}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{display:table}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{display:table}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{display:table}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{display:table}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{display:table}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{display:table}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{display:table}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{display:table}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{display:table}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{display:table}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{display:table}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{display:table}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{display:table}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{display:table}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/dist/chartist.min.js b/dist/chartist.min.js index d353e5a6..d05930dc 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,8 +1,9 @@ -/* Chartist.js 0.7.4 +/* Chartist.js 0.8.0 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.7.4"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)a[d]="object"!=typeof b[d]||b[d]instanceof Array?b[d]:c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a){var b,c,d={high:-Number.MAX_VALUE,low:Number.MAX_VALUE};for(b=0;bd.high&&(d.high=a[b][c]),a[b][c]j;;)if(k&&c.projectLength(a,i.step,i)<=d)i.step*=2;else{if(k||!(c.projectLength(a,i.step/2,i)>=d))break;i.step/=2}for(g=i.min,h=i.max,f=i.min;f<=i.max;f+=i.step)f+i.step=i.high&&(h-=i.step);for(i.min=g,i.max=h,i.range=i.max-i.min,i.values=[],f=i.min;f<=i.max;f+=i.step)i.values.push(c.roundWithPrecision(f));return i},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.axisY?b.axisY.offset||0:0,f=b.axisX?b.axisX.offset||0:0,g=c.stripUnit(b.width)||a.width(),h=c.stripUnit(b.height)||a.height(),i=c.normalizePadding(b.chartPadding,d);return{x1:i.left+e,y1:Math.max(h-i.bottom-f,i.bottom),x2:Math.max(g-i.right,i.right+e),y2:i.top,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}}},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)).map(a.transform),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){(l[k]||0===l[k])&&(j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,a.labelOffset,f,[h.classNames.label,h.classNames[a.units.dir]],g,i))})},c.optionsProvider=function(b,d,e){function f(b){var f=h;if(h=c.extend({},j),d)for(i=0;ig;g+=2){var i=[{x:+a[g-2],y:+a[g-1]},{x:+a[g],y:+a[g+1]},{x:+a[g+2],y:+a[g+3]},{x:+a[g+4],y:+a[g+5]}];b?g?h-4===g?i[3]={x:+a[0],y:+a[1]}:h-2===g&&(i[2]={x:+a[0],y:+a[1]},i[3]={x:+a[2],y:+a[3]}):i[0]={x:+a[h-2],y:+a[h-1]}:h-4===g?i[3]=i[2]:g||(i[0]={x:+a[g],y:+a[g+1]}),f.curve(d*(-i[0].x+6*i[1].x+i[2].x)/6+e*i[2].x,d*(-i[0].y+6*i[1].y+i[2].y)/6+e*i[2].y,d*(i[1].x+6*i[2].x-i[3].x)/6+e*i[2].x,d*(i[1].y+6*i[2].y-i[3].y)/6+e*i[2].y,i[2].x,i[2].y)}return f}}}(window,document,a),function(a,b,c){"use strict";c.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(window,document,a),function(a,b,c){"use strict";function d(a){var b=[];if(a.length)for(var c=0;ca.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return 0!==a}).length,n=0;n180,0,p.x,p.y);a.donut||r.line(l.x,l.y);var s=i[n].elem("path",{d:r.stringify()},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(s.attr({value:k[n]},c.xmlNs.uri),a.donut&&s.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,group:i[n],element:s,path:r.clone(),center:l,radius:e,startAngle:j,endAngle:o}),a.showLabel){var t=c.polarToCartesian(l.x,l.y,f,j+(o-j)/2),u=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n),v=i[n].elem("text",{dx:t.x,dy:t.y,"text-anchor":d(l,t,a.labelDirection)},a.classNames.label).text(""+u);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:v,text:""+u,x:t.x,y:t.y})}j=o}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.8.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=void 0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a,b){var c,d,e={high:void 0===b.high?-Number.MAX_VALUE:+b.high,low:void 0===b.low?Number.MAX_VALUE:+b.low},f=void 0===b.high,g=void 0===b.low;for(c=0;ce.high&&(e.high=a[c][d]),g&&a[c][d]k,m=f?c.rho(j.range):0;if(f&&c.projectLength(a,1,j)>=d)j.step=1;else if(f&&m=d)j.step=m;else for(;;)if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,f&&j.step%1!==0){j.step*=2;break}}for(h=j.min,i=j.max;h+j.step<=j.low;)h+=j.step;for(;i-j.step>=j.high;)i-=j.step;for(j.min=h,j.max=i,j.range=j.max-j.min,j.values=[],g=j.min;g<=j.max;g+=j.step)j.values.push(c.roundWithPrecision(g));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f-10,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){var m={x:0,y:0};(l[k]||0===l[k])&&("x"===a.units.pos?(b.pos=d.x1+b.pos,m.x=h.axisX.labelOffset.x,"start"===h.axisX.position?m.y=d.padding.top+h.axisX.labelOffset.y+(g?5:20):m.y=d.y1+h.axisX.labelOffset.y+(g?5:20)):(b.pos=d.y1-b.pos,m.y=h.axisY.labelOffset.y-(g?b.len:0),"start"===h.axisY.position?m.x=g?d.padding.left+h.axisY.labelOffset.x:d.x1-10:m.x=d.x2+h.axisY.labelOffset.x+10),j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,m,f,[h.classNames.label,h.classNames[a.units.dir],h.classNames[j.position]],g,i))})},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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;ga.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n),w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}j=p}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 58728afd..0ea5908d 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","localData","array","reversed","push","j","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","getBounds","scaleMinSpace","referenceValue","newMin","newMax","min","valueRange","oom","ceil","step","numberOfSteps","scaleUp","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","x","cos","y","sin","createChartRect","fallbackPadding","yOffset","axisY","xOffset","w","h","normalizedPadding","x1","y1","x2","y2","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","chartRect","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","transform","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener",{"end":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27784,"pos":27770,"col":10,"line":794,"value":"currentOptions","type":"name"},"start":{"file":"chartist.js","comments_before":[],"nlb":false,"endpos":27784,"pos":27770,"col":10,"line":794,"value":"currentOptions","type":"name"},"name":"currentOptions"},"Interpolation","none","pathCoordinates","path","Path","move","line","simple","defaultOptions","divisor","d","prevX","prevY","currX","currY","curve","cardinal","tension","t","c","z","iLen","p","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","name","attributes","parent","insertFirst","SVGElement","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","clientHeight","getBBox","clientWidth","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","toLowerCase","forEachParam","pathElement","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","position","count","arc","rx","ry","xAr","lAf","sf","chunks","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transformFnc","transformed","clone","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","valueIndex","showPoint","point","showLine","showArea","smoothing","lineSmooth","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","stackBars","serialSums","valueAxis","labelAxis","horizontalBars","fullHeight","zeroPoint","stackedBarValues","biPol","periodHalfLength","bar","previousStack","projected","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","start","end","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.7.4\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.7.4'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 {\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n var array = [],\n value,\n localData;\n\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n for (var i = 0; i < data.series.length; i++) {\n // If the series array contains an object with a data property we will use the property\n // otherwise the value directly (array or number).\n // We create a copy of the original data array with Array.prototype.push.apply\n localData = typeof(data.series[i]) === 'object' && data.series[i].data !== undefined ? data.series[i].data : data.series[i];\n if(localData instanceof Array) {\n array[i] = [];\n Array.prototype.push.apply(array[i], localData);\n } else {\n array[i] = localData;\n }\n\n // Convert object values to numbers\n for (var j = 0; j < array[i].length; j++) {\n value = array[i][j];\n value = value.value === 0 ? 0 : (value.value || value);\n array[i][j] = +value;\n }\n }\n\n return array;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = 0;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray) {\n var i,\n j,\n highLow = {\n high: -Number.MAX_VALUE,\n low: Number.MAX_VALUE\n };\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: 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(bounds.high === bounds.low) {\n // If both values are 0 we set high to 1\n if(bounds.low === 0) {\n bounds.high = 1;\n } else if(bounds.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n bounds.high = 0;\n } else {\n // If we have the same positive value for the bounds we set bounds.low to 0\n bounds.low = 0;\n }\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.low);\n }\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.min = Math.floor(bounds.low / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.max = Math.ceil(bounds.high / Math.pow(10, bounds.oom)) * Math.pow(10, bounds.oom);\n bounds.range = bounds.max - bounds.min;\n bounds.step = Math.pow(10, bounds.oom);\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 scaleUp = length < scaleMinSpace;\n\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 } else {\n break;\n }\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n if (i + bounds.step < bounds.low) {\n newMin += bounds.step;\n }\n\n if (i - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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 yOffset = options.axisY ? options.axisY.offset || 0 : 0,\n xOffset = options.axisX ? options.axisX.offset || 0 : 0,\n w = Chartist.stripUnit(options.width) || svg.width(),\n h = Chartist.stripUnit(options.height) || svg.height(),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding);\n\n return {\n x1: normalizedPadding.left + yOffset,\n y1: Math.max(h - normalizedPadding.bottom - xOffset, normalizedPadding.bottom),\n x2: Math.max(w - normalizedPadding.right, normalizedPadding.right + yOffset),\n y2: normalizedPadding.top,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement,\n positionalData = {};\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = axisOffset;\n\n if(useForeignObject) {\n var content = '' + labels[index] + '';\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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()],\n projectedValues = data.map(axis.projectValue.bind(axis)).map(axis.transform),\n labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\n return;\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, axis.labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir]\n ], useForeignObject, eventEmitter);\n }\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n get currentOptions() {\n return Chartist.extend({}, currentOptions);\n },\n removeMediaQueryListeners: removeMediaQueryListeners\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function cardinal(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 3; i < pathCoordinates.length; i += 2) {\n path.line(pathCoordinates[i - 1], pathCoordinates[i]);\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 * })\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 };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates) {\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]);\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2],\n prevY = pathCoordinates[i - 1],\n currX = pathCoordinates[i],\n currY = pathCoordinates[i + 1],\n length = (currX - prevX) * d;\n\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY\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 * })\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 };\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) {\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1]),\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 );\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 // 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.currentOptions);\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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.currentOptions);\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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|SVGElement} 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 SVGElement) {\n this._node = name;\n } else {\n this._node = document.createElementNS(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * @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 * @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 * @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 * @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 * 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', xhtmlNs);\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 with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(this._node.getBBox().height) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(this._node.getBBox().width) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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) {\n pathElements.splice(pos, 0, Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params));\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function arc(rx, ry, xAr, lAf, sf, x, y, relative) {\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);\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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 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 });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, transform, labelOffset, 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.transform = transform;\n this.labelOffset = labelOffset;\n this.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / (this.bounds.range + this.bounds.step),\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, transform, labelOffset, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n transform,\n labelOffset,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\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 },\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 // 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: 5,\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n\n var highLow = Chartist.getHighLow(normalizedData);\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 axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function xAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n }\n );\n\n var axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function yAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace\n }\n );\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n };\n pathCoordinates.push(p.x, p.y);\n\n //If we should show points we need to create them now to avoid secondary loop\n // Small offset for Firefox to render squares correctly\n if (options.showPoint) {\n var point = seriesGroups[seriesIndex].elem('line', {\n x1: p.x,\n y1: p.y,\n x2: p.x + 0.01,\n y2: p.y\n }, options.classNames.point).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: value,\n index: valueIndex,\n group: seriesGroups[seriesIndex],\n element: point,\n x: p.x,\n y: p.y\n });\n }\n }.bind(this));\n\n // TODO: Nicer handling of conditions, maybe composition?\n if (options.showLine || options.showArea) {\n var smoothing = typeof options.lineSmooth === 'function' ?\n options.lineSmooth : (options.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()),\n path = smoothing(pathCoordinates);\n\n if(options.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(options.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\n }\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 adition 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 // 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: 40\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 // 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 },\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 // 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 // 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 and 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 stackBars: false,\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 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-bar',\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 vertical: 'ct-vertical',\n horizontal: 'ct-horizontal'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var seriesGroups = [],\n normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length),\n normalizedPadding = Chartist.normalizePadding(options.chartPadding, defaultOptions.padding),\n highLow;\n\n // Create new svg element\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums]);\n } else {\n highLow = Chartist.getHighLow(normalizedData);\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 labelAxis,\n axisX,\n axisY;\n\n if(options.horizontalBars) {\n labelAxis = axisY = new Chartist.StepAxis(\n Chartist.Axis.units.y,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y - chartRect.height() / this.data.labels.length\n },\n {\n stepCount: this.data.labels.length,\n stretch: options.fullHeight\n }\n );\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.x,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n referenceValue: 0\n }\n );\n } else {\n labelAxis = axisX = new Chartist.StepAxis(\n Chartist.Axis.units.x,\n chartRect,\n function timeAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n return projectedValue;\n },\n {\n x: options.axisX.labelOffset.x,\n y: chartRect.y1 + options.axisX.labelOffset.y + (this.supportsForeignObject ? 5 : 20)\n },\n {\n stepCount: this.data.labels.length\n }\n );\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(\n Chartist.Axis.units.y,\n chartRect,\n function valueAxisTransform(projectedValue) {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n return projectedValue;\n },\n {\n x: normalizedPadding.left + options.axisY.labelOffset.x + (this.supportsForeignObject ? -10 : 0),\n y: options.axisY.labelOffset.y + (this.supportsForeignObject ? -15 : 0)\n },\n {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n referenceValue: 0\n }\n );\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength = chartRect[labelAxis.units.len]() / normalizedData[seriesIndex].length / 2;\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var projected = {\n x: chartRect.x1 + (options.horizontalBars ? valueAxis : labelAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - (options.horizontalBars ? labelAxis : valueAxis).projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n },\n bar,\n previousStack;\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n // Using bi-polar offset for multiple series if no stacked bars are used\n projected[labelAxis.units.pos] += options.stackBars ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name we add a custom attribute\n if(this.data.series[i].name) {\n seriesGroups[i].attr({\n 'series-name': this.data.series[i].name,\n 'meta': Chartist.serialize(this.data.series[i].meta)\n }, Chartist.xmlNs.uri);\n }\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (this.data.series[i].className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].elem('path', {\n d: path.stringify()\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'value': dataArray[i]\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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 objects that contain a data property with the value 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\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * data: 20,\n * className: 'my-custom-class-one'\n * }, {\n * data: 10,\n * className: 'my-custom-class-two'\n * }, {\n * data: 70,\n * className: 'my-custom-class-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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","recursiveConvert","isNaN","hasOwnProperty","reversed","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","j","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","findHigh","findLow","rho","num","gcd","p","q","f","x","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","y","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","attributes","parent","insertFirst","Element","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","joinedPath","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","smoothing","point","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisStepCount","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.8.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.8.0'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n // Rcursively 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(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) {\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n return +value;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = undefined;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray, options) {\n var i,\n j,\n highLow = {\n high: options.high === undefined ? -Number.MAX_VALUE : +options.high,\n low: options.low === undefined ? Number.MAX_VALUE : +options.low\n },\n findHigh = options.high === undefined,\n findLow = options.low === undefined;\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (findHigh && dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (findLow && dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\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 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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 }\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = 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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()];\n var projectedValues = data.map(axis.projectValue.bind(axis));\n var labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\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(axis.units.pos === 'x') {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n labelOffset.x = options.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(options.axisX.position === 'start') {\n labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 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(options.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10;\n } else {\n labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir],\n options.classNames[axisOptions.position]\n ], useForeignObject, eventEmitter);\n }\n });\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 * 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 });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n Chartist.Svg.Path.join = join;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, 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.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / this.bounds.range,\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 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 // 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 // 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 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 seriesGroups = [];\n var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var highLow = Chartist.getHighLow(normalizedData, options);\n\n var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n });\n\n var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger\n });\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\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 };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : 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 = seriesGroups[seriesIndex].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 'value': pathElement.data.value,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 group: seriesGroups[seriesIndex],\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(seriesOptions.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 seriesGroups = [];\n var data = Chartist.getDataArray(this.data, options.reverseData);\n var normalizedData = options.distributeSeries ? data.map(function(value) {\n return [value];\n }) : Chartist.normalizeDataArray(data, this.data.labels.length);\n var highLow;\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 if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(normalizedData, options);\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 labelAxisStepCount,\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 but stacked bars aren't, we need to use the one dimensional series array\n // length as step count for the label axis\n labelAxisStepCount = normalizedData.length;\n } else 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 set step\n // count to 1\n labelAxisStepCount = 1;\n } else {\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length\n // as the bars are normalized\n labelAxisStepCount = this.data.labels.length;\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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n onlyInteger: options.axisX.onlyInteger,\n referenceValue: 0\n });\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger,\n referenceValue: 0\n });\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength;\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 / normalizedData.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 / normalizedData[seriesIndex].length / 2;\n }\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[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, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].elem('path', {\n d: path.stringify()\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/dist/scss/chartist.scss b/dist/scss/chartist.scss index 2456997b..aaeb6953 100644 --- a/dist/scss/chartist.scss +++ b/dist/scss/chartist.scss @@ -28,14 +28,40 @@ } } -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-align: $ct-text-align) { +@mixin ct-align-justify($ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) { + -webkit-box-align: $ct-text-align; + -webkit-align-items: $ct-text-align; + -ms-flex-align: $ct-text-align; + align-items: $ct-text-align; + -webkit-box-pack: $ct-text-justify; + -webkit-justify-content: $ct-text-justify; + -ms-flex-pack: $ct-text-justify; + justify-content: $ct-text-justify; + // Fallback to text-align for non-flex browsers + @if($ct-text-justify == 'flex-start') { + text-align: left; + } @else if ($ct-text-justify == 'flex-end') { + text-align: right; + } @else { + text-align: center; + } +} + +@mixin ct-flex() { + // Fallback to block display: block; - width: 100%; - height: 100%; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; +} + +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) { fill: $ct-text-color; color: $ct-text-color; font-size: $ct-text-size; - text-align: $ct-text-align; + line-height: $ct-text-line-height; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { @@ -86,17 +112,76 @@ } } -@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-horizontal-text-align: $ct-horizontal-text-align, $ct-vertical-text-align: $ct-vertical-text-align, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { +@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { + .#{$ct-class-label} { @include ct-chart-label($ct-text-color, $ct-text-size); } - .#{$ct-class-label}.#{$ct-class-horizontal} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-horizontal-text-align); + .#{$ct-class-chart-line} .#{$ct-class-label}, + .#{$ct-class-chart-bar} .#{$ct-class-label} { + @include ct-flex(); + } + + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-end); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; + } + + .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { + @include ct-align-justify(flex-end, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, center); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, center); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { + //@include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify); + @include ct-align-justify(center, flex-end); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; } - .#{$ct-class-label}.#{$ct-class-vertical} { - @include ct-chart-label($ct-text-color, $ct-text-size, $ct-vertical-text-align); + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { + @include ct-align-justify(center, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; } .#{$ct-class-grid} { diff --git a/dist/scss/settings/_chartist-settings.scss b/dist/scss/settings/_chartist-settings.scss index b244b592..af242f49 100644 --- a/dist/scss/settings/_chartist-settings.scss +++ b/dist/scss/settings/_chartist-settings.scss @@ -6,6 +6,7 @@ $ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, $ct-class-chart: ct-chart !default; $ct-class-chart-line: ct-chart-line !default; $ct-class-chart-bar: ct-chart-bar !default; +$ct-class-horizontal-bars: ct-horizontal-bars !default; $ct-class-chart-pie: ct-chart-pie !default; $ct-class-label: ct-label !default; $ct-class-series: ct-series !default; @@ -18,6 +19,8 @@ $ct-class-donut: ct-donut !default; $ct-class-grid: ct-grid !default; $ct-class-vertical: ct-vertical !default; $ct-class-horizontal: ct-horizontal !default; +$ct-class-start: ct-start !default; +$ct-class-end: ct-end !default; // Container ratio $ct-container-ratio: (1/1.618) !default; @@ -25,9 +28,9 @@ $ct-container-ratio: (1/1.618) !default; // Text styles for labels $ct-text-color: rgba(0, 0, 0, 0.4) !default; $ct-text-size: 0.75rem !default; -$ct-text-align: left !default; -$ct-horizontal-text-align: left !default; -$ct-vertical-text-align: right !default; +$ct-text-align: flex-start !default; +$ct-text-justify: flex-start !default; +$ct-text-line-height: 1; // Grid styles $ct-grid-color: rgba(0, 0, 0, 0.2) !default; diff --git a/package.json b/package.json index bb7bb227..25fa3b59 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.7.4", + "version": "0.8.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 4d22f26b4af89d74cac7924677bc7a96810d3c6d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 04:49:44 +0200 Subject: [PATCH 250/593] Removed resolution --- bower.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bower.json b/bower.json index 3c8cd0ec..87088bd5 100644 --- a/bower.json +++ b/bower.json @@ -28,8 +28,5 @@ "site", "src", "test" - ], - "resolutions": { - "chartist": "~0.8.0" - } + ] } From e494ed13da674be19f82166e37f5f146e0746aeb Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 10 May 2015 05:04:10 +0200 Subject: [PATCH 251/593] documentation: Fixed bower dependencies for documentation site --- bower.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bower.json b/bower.json index 87088bd5..9d06e799 100644 --- a/bower.json +++ b/bower.json @@ -12,9 +12,9 @@ "compass-mixins": "~1.0.2", "codemirror": "~4.12.0", "base64": "~0.3.0", - "chartist-plugin-pointlabels": "~0.0.2", - "chartist-plugin-sketchy": "~0.0.1", - "chartist-plugin-accessibility": "~0.0.1", + "chartist-plugin-pointlabels": "~0.0.3", + "chartist-plugin-sketchy": "~0.0.2", + "chartist-plugin-accessibility": "~0.0.2", "chartist-plugin-tooltip": "~0.0.8", "matchMedia": "~0.2.0" }, @@ -28,5 +28,8 @@ "site", "src", "test" - ] + ], + "resolutions": { + "chartist": "~0.8.0" + } } From 5e3728b709e84468e026434fa218c319d1bece79 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 12 May 2015 21:13:05 +0200 Subject: [PATCH 252/593] Added default styles for alignment-baseline --- src/styles/chartist.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index aaeb6953..fe68f886 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -62,6 +62,7 @@ color: $ct-text-color; font-size: $ct-text-size; line-height: $ct-text-line-height; + alignment-baseline: middle; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { From 4bb0ac89df7a031a43bdab8ad22643ac5a2fa30b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 12 May 2015 21:52:17 +0200 Subject: [PATCH 253/593] Fixed bug with Pie chart and labelInterpolationFnc, fixes #316 --- src/scripts/charts/pie.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 8c638570..41c32342 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -195,22 +195,24 @@ var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); - var labelElement = seriesGroups[i].elem('text', { - dx: labelPosition.x, - dy: labelPosition.y, - 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) - }, options.classNames.label).text('' + interpolatedValue); + if(interpolatedValue || interpolatedValue === 0) { + var labelElement = seriesGroups[i].elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); - // Fire off draw event - this.eventEmitter.emit('draw', { - type: 'label', - index: i, - group: seriesGroups[i], - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y - }); + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } } // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues From 6da81f07d701788cfd745a87ddf2c10eb7666456 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 12 May 2015 22:12:27 +0200 Subject: [PATCH 254/593] Added new option labelPosition for Pie charts to have better control over label placement, fixes #315 --- src/scripts/charts/pie.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 41c32342..477ba965 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -39,6 +39,8 @@ showLabel: true, // 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. labelOffset: 0, + // 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. + labelPosition: 'inside', // An interpolation function for the label value labelInterpolationFnc: Chartist.noop, // 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. @@ -99,9 +101,18 @@ // See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html radius -= options.donut ? options.donutWidth / 2 : 0; - // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius - // see https://github.com/gionkunz/chartist-js/issues/21 - labelRadius = options.donut ? radius : radius / 2; + // 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) { + 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 { + // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie + // slice + labelRadius = radius / 2; + } // Add the offset to the labelRadius where a negative offset means closed to the center of the chart labelRadius += options.labelOffset; From 0d66139b6e7b334f120c2e0590c3cf5b1a8882ec Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 May 2015 00:08:32 +0200 Subject: [PATCH 255/593] Added fix for Chartist.rho that caused endless loop when called with 1, fixes #318 --- src/scripts/core.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scripts/core.js b/src/scripts/core.js index 65143166..9aac7b9a 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -476,6 +476,10 @@ var Chartist = { * @returns {Number} The smallest integer factor of the parameter num. */ Chartist.rho = function(num) { + if(num === 1) { + return num; + } + function gcd(p, q) { if (p % q === 0) { return q; From da84029b2c4a2b8f1552ceff055ec793d99f4809 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 May 2015 01:36:01 +0200 Subject: [PATCH 256/593] Refactored getHighLow to use recursion in order to enable more dynamic array structures --- src/scripts/core.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 9aac7b9a..c597ce48 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -429,27 +429,33 @@ var Chartist = { * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ Chartist.getHighLow = function (dataArray, options) { - var i, - j, - highLow = { + var highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low }, findHigh = options.high === undefined, findLow = options.low === undefined; - for (i = 0; i < dataArray.length; i++) { - for (j = 0; j < dataArray[i].length; j++) { - if (findHigh && dataArray[i][j] > highLow.high) { - highLow.high = dataArray[i][j]; + // Function to recursively walk through arrays and find highest and lowest number + function recursiveHighLow(data) { + if(data instanceof Array) { + for (var i = 0; i < data.length; i++) { + recursiveHighLow(data[i]); + } + } else { + if (findHigh && data > highLow.high) { + highLow.high = data; } - if (findLow && dataArray[i][j] < highLow.low) { - highLow.low = dataArray[i][j]; + if (findLow && data < highLow.low) { + highLow.low = data; } } } + // Start to find highest and lowest number recursively + recursiveHighLow(dataArray); + // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity if (highLow.high <= highLow.low) { From e1b44fa1e2ffcc4e965230e7a003e0bd00625dbc Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 May 2015 02:03:39 +0200 Subject: [PATCH 257/593] Added better support for undefined values in bar charts --- src/scripts/charts/bar.js | 13 +++++++++---- src/scripts/core.js | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 6455564c..d7d0e0fa 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -271,13 +271,13 @@ // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos } } @@ -290,6 +290,11 @@ previousStack = stackedBarValues[valueIndex] || zeroPoint; stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); + // Skip if value is undefined + if(value === undefined) { + return; + } + var positions = {}; positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; diff --git a/src/scripts/core.js b/src/scripts/core.js index c597ce48..e8c91833 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -133,7 +133,7 @@ var Chartist = { * @return {*} */ Chartist.sum = function(previous, current) { - return previous + current; + return previous + (current ? current : 0); }; /** From 1517d8ee940ff4a4186046ba32252002b1eee1f9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 2 Jun 2015 20:54:30 +0200 Subject: [PATCH 258/593] Version bump and changelog for 0.8.1 --- CHANGELOG.md | 8 ++++++++ bower.json | 2 +- package.json | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38dee11b..200550ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +v0.8.1 - 02 Jun 2015 +-------------------- +- Added new option labelPosition for Pie charts to have better control over label placement, fixes #315 +- Added default styles for alignment-baseline +- Added better support for undefined values in bar charts +- Refactored getHighLow to use recursion in order to enable more dynamic array structures and better edge case management +- Fixed issue with Chartist.rho that caused endless loop when called with 1, fixes #318 + v0.8.0 - 10 May 2015 -------------------- - Added new option to bar charts to allow a series distribution and use a simple one dimensional array for data (#209) diff --git a/bower.json b/bower.json index 9d06e799..da220968 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.8.0", + "version": "0.8.1", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/package.json b/package.json index 25fa3b59..72b5e94c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.8.0", + "version": "0.8.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From c05e2def46ccf5e558358af5767afbc0aa8bd69a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 2 Jun 2015 20:58:33 +0200 Subject: [PATCH 259/593] Fixed broken release 0.8.1 --- CHANGELOG.md | 6 ++- bower.json | 2 +- dist/chartist.js | 96 ++++++++++++++++++++++++++-------------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 6 +-- dist/chartist.min.js.map | 2 +- dist/scss/chartist.scss | 1 + package.json | 2 +- 8 files changed, 75 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 200550ed..1af02ac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ -v0.8.1 - 02 Jun 2015 +v0.8.2 - 02 Jun 2015 -------------------- +- Fixed broken release 0.8.1 + +v0.8.1 - 02 Jun 2015 (BROKEN!) +------------------------------ - Added new option labelPosition for Pie charts to have better control over label placement, fixes #315 - Added default styles for alignment-baseline - Added better support for undefined values in bar charts diff --git a/bower.json b/bower.json index da220968..fa81a6a5 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.8.1", + "version": "0.8.2", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index fd6823cc..7d6a4cd1 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.8.0 +/* Chartist.js 0.8.2 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.8.0' + version: '0.8.2' }; (function (window, document, Chartist) { @@ -154,7 +154,7 @@ var Chartist = { * @return {*} */ Chartist.sum = function(previous, current) { - return previous + current; + return previous + (current ? current : 0); }; /** @@ -450,27 +450,33 @@ var Chartist = { * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ Chartist.getHighLow = function (dataArray, options) { - var i, - j, - highLow = { + var highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low }, findHigh = options.high === undefined, findLow = options.low === undefined; - for (i = 0; i < dataArray.length; i++) { - for (j = 0; j < dataArray[i].length; j++) { - if (findHigh && dataArray[i][j] > highLow.high) { - highLow.high = dataArray[i][j]; + // Function to recursively walk through arrays and find highest and lowest number + function recursiveHighLow(data) { + if(data instanceof Array) { + for (var i = 0; i < data.length; i++) { + recursiveHighLow(data[i]); + } + } else { + if (findHigh && data > highLow.high) { + highLow.high = data; } - if (findLow && dataArray[i][j] < highLow.low) { - highLow.low = dataArray[i][j]; + if (findLow && data < highLow.low) { + highLow.low = data; } } } + // Start to find highest and lowest number recursively + recursiveHighLow(dataArray); + // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity if (highLow.high <= highLow.low) { @@ -497,6 +503,10 @@ var Chartist = { * @returns {Number} The smallest integer factor of the parameter num. */ Chartist.rho = function(num) { + if(num === 1) { + return num; + } + function gcd(p, q) { if (p % q === 0) { return q; @@ -3376,13 +3386,13 @@ var Chartist = { // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos, + y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos } } @@ -3395,6 +3405,11 @@ var Chartist = { previousStack = stackedBarValues[valueIndex] || zeroPoint; stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); + // Skip if value is undefined + if(value === undefined) { + return; + } + var positions = {}; positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; @@ -3525,6 +3540,8 @@ var Chartist = { showLabel: true, // 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. labelOffset: 0, + // 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. + labelPosition: 'inside', // An interpolation function for the label value labelInterpolationFnc: Chartist.noop, // 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. @@ -3585,9 +3602,18 @@ var Chartist = { // See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html radius -= options.donut ? options.donutWidth / 2 : 0; - // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius - // see https://github.com/gionkunz/chartist-js/issues/21 - labelRadius = options.donut ? radius : radius / 2; + // 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) { + 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 { + // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie + // slice + labelRadius = radius / 2; + } // Add the offset to the labelRadius where a negative offset means closed to the center of the chart labelRadius += options.labelOffset; @@ -3681,22 +3707,24 @@ var Chartist = { var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); - var labelElement = seriesGroups[i].elem('text', { - dx: labelPosition.x, - dy: labelPosition.y, - 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) - }, options.classNames.label).text('' + interpolatedValue); + if(interpolatedValue || interpolatedValue === 0) { + var labelElement = seriesGroups[i].elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); - // Fire off draw event - this.eventEmitter.emit('draw', { - type: 'label', - index: i, - group: seriesGroups[i], - element: labelElement, - text: '' + interpolatedValue, - x: labelPosition.x, - y: labelPosition.y - }); + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: i, + group: seriesGroups[i], + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } } // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues diff --git a/dist/chartist.min.css b/dist/chartist.min.css index fbf4d61c..0690662b 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1 +1 @@ -.ct-chart.ct-double-octave:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-second:after,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-third:after,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-third:after,.ct-chart.ct-octave:after,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-square:after{content:"";clear:both}.ct-chart.ct-double-octave:after,.ct-chart.ct-double-octave:before,.ct-chart.ct-golden-section:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-eleventh:before,.ct-chart.ct-major-second:after,.ct-chart.ct-major-second:before,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-seventh:before,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-sixth:before,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-tenth:before,.ct-chart.ct-major-third:after,.ct-chart.ct-major-third:before,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-major-twelfth:before,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-second:before,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-seventh:before,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-sixth:before,.ct-chart.ct-minor-third:after,.ct-chart.ct-minor-third:before,.ct-chart.ct-octave:after,.ct-chart.ct-octave:before,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fifth:before,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-perfect-fourth:before,.ct-chart.ct-square:after,.ct-chart.ct-square:before{content:""}.ct-chart .ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart .ct-chart-bar .ct-label,.ct-chart .ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart .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 .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 .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-chart .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 .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 .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 .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 .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 .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 .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-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#f4c63d}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#f4c63d}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#d17905}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#d17905}.ct-chart .ct-series.ct-series-e .ct-bar,.ct-chart .ct-series.ct-series-e .ct-line,.ct-chart .ct-series.ct-series-e .ct-point,.ct-chart .ct-series.ct-series-e .ct-slice.ct-donut{stroke:#453d3f}.ct-chart .ct-series.ct-series-e .ct-area,.ct-chart .ct-series.ct-series-e .ct-slice:not(.ct-donut){fill:#453d3f}.ct-chart .ct-series.ct-series-f .ct-bar,.ct-chart .ct-series.ct-series-f .ct-line,.ct-chart .ct-series.ct-series-f .ct-point,.ct-chart .ct-series.ct-series-f .ct-slice.ct-donut{stroke:#59922b}.ct-chart .ct-series.ct-series-f .ct-area,.ct-chart .ct-series.ct-series-f .ct-slice:not(.ct-donut){fill:#59922b}.ct-chart .ct-series.ct-series-g .ct-bar,.ct-chart .ct-series.ct-series-g .ct-line,.ct-chart .ct-series.ct-series-g .ct-point,.ct-chart .ct-series.ct-series-g .ct-slice.ct-donut{stroke:#0544d3}.ct-chart .ct-series.ct-series-g .ct-area,.ct-chart .ct-series.ct-series-g .ct-slice:not(.ct-donut){fill:#0544d3}.ct-chart .ct-series.ct-series-h .ct-bar,.ct-chart .ct-series.ct-series-h .ct-line,.ct-chart .ct-series.ct-series-h .ct-point,.ct-chart .ct-series.ct-series-h .ct-slice.ct-donut{stroke:#6b0392}.ct-chart .ct-series.ct-series-h .ct-area,.ct-chart .ct-series.ct-series-h .ct-slice:not(.ct-donut){fill:#6b0392}.ct-chart .ct-series.ct-series-i .ct-bar,.ct-chart .ct-series.ct-series-i .ct-line,.ct-chart .ct-series.ct-series-i .ct-point,.ct-chart .ct-series.ct-series-i .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-i .ct-area,.ct-chart .ct-series.ct-series-i .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-j .ct-bar,.ct-chart .ct-series.ct-series-j .ct-line,.ct-chart .ct-series.ct-series-j .ct-point,.ct-chart .ct-series.ct-series-j .ct-slice.ct-donut{stroke:#dda458}.ct-chart .ct-series.ct-series-j .ct-area,.ct-chart .ct-series.ct-series-j .ct-slice:not(.ct-donut){fill:#dda458}.ct-chart .ct-series.ct-series-k .ct-bar,.ct-chart .ct-series.ct-series-k .ct-line,.ct-chart .ct-series.ct-series-k .ct-point,.ct-chart .ct-series.ct-series-k .ct-slice.ct-donut{stroke:#eacf7d}.ct-chart .ct-series.ct-series-k .ct-area,.ct-chart .ct-series.ct-series-k .ct-slice:not(.ct-donut){fill:#eacf7d}.ct-chart .ct-series.ct-series-l .ct-bar,.ct-chart .ct-series.ct-series-l .ct-line,.ct-chart .ct-series.ct-series-l .ct-point,.ct-chart .ct-series.ct-series-l .ct-slice.ct-donut{stroke:#86797d}.ct-chart .ct-series.ct-series-l .ct-area,.ct-chart .ct-series.ct-series-l .ct-slice:not(.ct-donut){fill:#86797d}.ct-chart .ct-series.ct-series-m .ct-bar,.ct-chart .ct-series.ct-series-m .ct-line,.ct-chart .ct-series.ct-series-m .ct-point,.ct-chart .ct-series.ct-series-m .ct-slice.ct-donut{stroke:#b2c326}.ct-chart .ct-series.ct-series-m .ct-area,.ct-chart .ct-series.ct-series-m .ct-slice:not(.ct-donut){fill:#b2c326}.ct-chart .ct-series.ct-series-n .ct-bar,.ct-chart .ct-series.ct-series-n .ct-line,.ct-chart .ct-series.ct-series-n .ct-point,.ct-chart .ct-series.ct-series-n .ct-slice.ct-donut{stroke:#6188e2}.ct-chart .ct-series.ct-series-n .ct-area,.ct-chart .ct-series.ct-series-n .ct-slice:not(.ct-donut){fill:#6188e2}.ct-chart .ct-series.ct-series-o .ct-bar,.ct-chart .ct-series.ct-series-o .ct-line,.ct-chart .ct-series.ct-series-o .ct-point,.ct-chart .ct-series.ct-series-o .ct-slice.ct-donut{stroke:#a748ca}.ct-chart .ct-series.ct-series-o .ct-area,.ct-chart .ct-series.ct-series-o .ct-slice:not(.ct-donut){fill:#a748ca}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{display:table}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{display:table}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{display:table}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{display:table}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{display:table}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{display:table}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{display:table}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{display:table}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{display:table}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{display:table}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{display:table}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{display:table}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{display:table}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{display:table}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{display:table}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{display:table}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file +.ct-chart.ct-double-octave:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-second:after,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-third:after,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-third:after,.ct-chart.ct-octave:after,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-square:after{content:"";clear:both}.ct-chart.ct-double-octave:after,.ct-chart.ct-double-octave:before,.ct-chart.ct-golden-section:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-eleventh:before,.ct-chart.ct-major-second:after,.ct-chart.ct-major-second:before,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-seventh:before,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-sixth:before,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-tenth:before,.ct-chart.ct-major-third:after,.ct-chart.ct-major-third:before,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-major-twelfth:before,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-second:before,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-seventh:before,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-sixth:before,.ct-chart.ct-minor-third:after,.ct-chart.ct-minor-third:before,.ct-chart.ct-octave:after,.ct-chart.ct-octave:before,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fifth:before,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-perfect-fourth:before,.ct-chart.ct-square:after,.ct-chart.ct-square:before{content:""}.ct-chart .ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1;alignment-baseline:middle}.ct-chart .ct-chart-bar .ct-label,.ct-chart .ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart .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 .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 .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-chart .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 .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 .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 .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 .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 .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 .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-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#f4c63d}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#f4c63d}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#d17905}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#d17905}.ct-chart .ct-series.ct-series-e .ct-bar,.ct-chart .ct-series.ct-series-e .ct-line,.ct-chart .ct-series.ct-series-e .ct-point,.ct-chart .ct-series.ct-series-e .ct-slice.ct-donut{stroke:#453d3f}.ct-chart .ct-series.ct-series-e .ct-area,.ct-chart .ct-series.ct-series-e .ct-slice:not(.ct-donut){fill:#453d3f}.ct-chart .ct-series.ct-series-f .ct-bar,.ct-chart .ct-series.ct-series-f .ct-line,.ct-chart .ct-series.ct-series-f .ct-point,.ct-chart .ct-series.ct-series-f .ct-slice.ct-donut{stroke:#59922b}.ct-chart .ct-series.ct-series-f .ct-area,.ct-chart .ct-series.ct-series-f .ct-slice:not(.ct-donut){fill:#59922b}.ct-chart .ct-series.ct-series-g .ct-bar,.ct-chart .ct-series.ct-series-g .ct-line,.ct-chart .ct-series.ct-series-g .ct-point,.ct-chart .ct-series.ct-series-g .ct-slice.ct-donut{stroke:#0544d3}.ct-chart .ct-series.ct-series-g .ct-area,.ct-chart .ct-series.ct-series-g .ct-slice:not(.ct-donut){fill:#0544d3}.ct-chart .ct-series.ct-series-h .ct-bar,.ct-chart .ct-series.ct-series-h .ct-line,.ct-chart .ct-series.ct-series-h .ct-point,.ct-chart .ct-series.ct-series-h .ct-slice.ct-donut{stroke:#6b0392}.ct-chart .ct-series.ct-series-h .ct-area,.ct-chart .ct-series.ct-series-h .ct-slice:not(.ct-donut){fill:#6b0392}.ct-chart .ct-series.ct-series-i .ct-bar,.ct-chart .ct-series.ct-series-i .ct-line,.ct-chart .ct-series.ct-series-i .ct-point,.ct-chart .ct-series.ct-series-i .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-i .ct-area,.ct-chart .ct-series.ct-series-i .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-j .ct-bar,.ct-chart .ct-series.ct-series-j .ct-line,.ct-chart .ct-series.ct-series-j .ct-point,.ct-chart .ct-series.ct-series-j .ct-slice.ct-donut{stroke:#dda458}.ct-chart .ct-series.ct-series-j .ct-area,.ct-chart .ct-series.ct-series-j .ct-slice:not(.ct-donut){fill:#dda458}.ct-chart .ct-series.ct-series-k .ct-bar,.ct-chart .ct-series.ct-series-k .ct-line,.ct-chart .ct-series.ct-series-k .ct-point,.ct-chart .ct-series.ct-series-k .ct-slice.ct-donut{stroke:#eacf7d}.ct-chart .ct-series.ct-series-k .ct-area,.ct-chart .ct-series.ct-series-k .ct-slice:not(.ct-donut){fill:#eacf7d}.ct-chart .ct-series.ct-series-l .ct-bar,.ct-chart .ct-series.ct-series-l .ct-line,.ct-chart .ct-series.ct-series-l .ct-point,.ct-chart .ct-series.ct-series-l .ct-slice.ct-donut{stroke:#86797d}.ct-chart .ct-series.ct-series-l .ct-area,.ct-chart .ct-series.ct-series-l .ct-slice:not(.ct-donut){fill:#86797d}.ct-chart .ct-series.ct-series-m .ct-bar,.ct-chart .ct-series.ct-series-m .ct-line,.ct-chart .ct-series.ct-series-m .ct-point,.ct-chart .ct-series.ct-series-m .ct-slice.ct-donut{stroke:#b2c326}.ct-chart .ct-series.ct-series-m .ct-area,.ct-chart .ct-series.ct-series-m .ct-slice:not(.ct-donut){fill:#b2c326}.ct-chart .ct-series.ct-series-n .ct-bar,.ct-chart .ct-series.ct-series-n .ct-line,.ct-chart .ct-series.ct-series-n .ct-point,.ct-chart .ct-series.ct-series-n .ct-slice.ct-donut{stroke:#6188e2}.ct-chart .ct-series.ct-series-n .ct-area,.ct-chart .ct-series.ct-series-n .ct-slice:not(.ct-donut){fill:#6188e2}.ct-chart .ct-series.ct-series-o .ct-bar,.ct-chart .ct-series.ct-series-o .ct-line,.ct-chart .ct-series.ct-series-o .ct-point,.ct-chart .ct-series.ct-series-o .ct-slice.ct-donut{stroke:#a748ca}.ct-chart .ct-series.ct-series-o .ct-area,.ct-chart .ct-series.ct-series-o .ct-slice:not(.ct-donut){fill:#a748ca}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{display:table}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{display:table}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{display:table}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{display:table}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{display:table}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{display:table}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{display:table}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{display:table}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{display:table}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{display:table}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{display:table}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{display:table}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{display:table}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{display:table}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{display:table}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{display:table}.ct-chart.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/dist/chartist.min.js b/dist/chartist.min.js index d05930dc..22ddf09e 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.8.0 +/* Chartist.js 0.8.2 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.8.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+b},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=void 0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a,b){var c,d,e={high:void 0===b.high?-Number.MAX_VALUE:+b.high,low:void 0===b.low?Number.MAX_VALUE:+b.low},f=void 0===b.high,g=void 0===b.low;for(c=0;ce.high&&(e.high=a[c][d]),g&&a[c][d]k,m=f?c.rho(j.range):0;if(f&&c.projectLength(a,1,j)>=d)j.step=1;else if(f&&m=d)j.step=m;else for(;;)if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,f&&j.step%1!==0){j.step*=2;break}}for(h=j.min,i=j.max;h+j.step<=j.low;)h+=j.step;for(;i-j.step>=j.high;)i-=j.step;for(j.min=h,j.max=i,j.range=j.max-j.min,j.values=[],g=j.min;g<=j.max;g+=j.step)j.values.push(c.roundWithPrecision(g));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f-10,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){var m={x:0,y:0};(l[k]||0===l[k])&&("x"===a.units.pos?(b.pos=d.x1+b.pos,m.x=h.axisX.labelOffset.x,"start"===h.axisX.position?m.y=d.padding.top+h.axisX.labelOffset.y+(g?5:20):m.y=d.y1+h.axisX.labelOffset.y+(g?5:20)):(b.pos=d.y1-b.pos,m.y=h.axisY.labelOffset.y-(g?b.len:0),"start"===h.axisY.position?m.x=g?d.padding.left+h.axisY.labelOffset.x:d.x1-10:m.x=d.x2+h.axisY.labelOffset.x+10),j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,m,f,[h.classNames.label,h.classNames[a.units.dir],h.classNames[j.position]],g,i))})},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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;ga.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f=a.donut?e:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n),w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}j=p}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.8.2"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=void 0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a,b){function c(a){if(a instanceof Array)for(var b=0;bd.high&&(d.high=a),f&&ak,m=f?c.rho(j.range):0;if(f&&c.projectLength(a,1,j)>=d)j.step=1;else if(f&&m=d)j.step=m;else for(;;)if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,f&&j.step%1!==0){j.step*=2;break}}for(h=j.min,i=j.max;h+j.step<=j.low;)h+=j.step;for(;i-j.step>=j.high;)i-=j.step;for(j.min=h,j.max=i,j.range=j.max-j.min,j.values=[],g=j.min;g<=j.max;g+=j.step)j.values.push(c.roundWithPrecision(g));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f-10,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){var m={x:0,y:0};(l[k]||0===l[k])&&("x"===a.units.pos?(b.pos=d.x1+b.pos,m.x=h.axisX.labelOffset.x,"start"===h.axisX.position?m.y=d.padding.top+h.axisX.labelOffset.y+(g?5:20):m.y=d.y1+h.axisX.labelOffset.y+(g?5:20)):(b.pos=d.y1-b.pos,m.y=h.axisY.labelOffset.y-(g?b.len:0),"start"===h.axisY.position?m.x=g?d.padding.left+h.axisY.labelOffset.x:d.x1-10:m.x=d.x2+h.axisY.labelOffset.x+10),j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,m,f,[h.classNames.label,h.classNames[a.units.dir],h.classNames[j.position]],g,i))})},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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;ga.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label", +index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 0ea5908d..e6576344 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","recursiveConvert","isNaN","hasOwnProperty","reversed","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","j","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","highLow","high","Number","MAX_VALUE","low","findHigh","findLow","rho","num","gcd","p","q","f","x","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","y","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","attributes","parent","insertFirst","Element","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","joinedPath","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","smoothing","point","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisStepCount","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","hasSingleValInSeries","val","endAngle","labelPosition","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.8.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.8.0'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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;\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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n // Rcursively 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(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) {\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n return +value;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = undefined;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray, options) {\n var i,\n j,\n highLow = {\n high: options.high === undefined ? -Number.MAX_VALUE : +options.high,\n low: options.low === undefined ? Number.MAX_VALUE : +options.low\n },\n findHigh = options.high === undefined,\n findLow = options.low === undefined;\n\n for (i = 0; i < dataArray.length; i++) {\n for (j = 0; j < dataArray[i].length; j++) {\n if (findHigh && dataArray[i][j] > highLow.high) {\n highLow.high = dataArray[i][j];\n }\n\n if (findLow && dataArray[i][j] < highLow.low) {\n highLow.low = dataArray[i][j];\n }\n }\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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\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 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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 }\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = 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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()];\n var projectedValues = data.map(axis.projectValue.bind(axis));\n var labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\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(axis.units.pos === 'x') {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n labelOffset.x = options.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(options.axisX.position === 'start') {\n labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 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(options.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10;\n } else {\n labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir],\n options.classNames[axisOptions.position]\n ], useForeignObject, eventEmitter);\n }\n });\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 * 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 });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n Chartist.Svg.Path.join = join;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, 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.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / this.bounds.range,\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 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 // 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 // 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 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 seriesGroups = [];\n var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var highLow = Chartist.getHighLow(normalizedData, options);\n\n var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n });\n\n var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger\n });\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\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 };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : 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 = seriesGroups[seriesIndex].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 'value': pathElement.data.value,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 group: seriesGroups[seriesIndex],\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(seriesOptions.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 seriesGroups = [];\n var data = Chartist.getDataArray(this.data, options.reverseData);\n var normalizedData = options.distributeSeries ? data.map(function(value) {\n return [value];\n }) : Chartist.normalizeDataArray(data, this.data.labels.length);\n var highLow;\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 if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(normalizedData, options);\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 labelAxisStepCount,\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 but stacked bars aren't, we need to use the one dimensional series array\n // length as step count for the label axis\n labelAxisStepCount = normalizedData.length;\n } else 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 set step\n // count to 1\n labelAxisStepCount = 1;\n } else {\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length\n // as the bars are normalized\n labelAxisStepCount = this.data.labels.length;\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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n onlyInteger: options.axisX.onlyInteger,\n referenceValue: 0\n });\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger,\n referenceValue: 0\n });\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength;\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 / normalizedData.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 / normalizedData[seriesIndex].length / 2;\n }\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[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, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value, labelAxisValueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - valueAxis.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 // 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 2 : 0;\n\n // If a donut chart then the label position is at the radius, if regular pie chart it's half of the radius\n // see https://github.com/gionkunz/chartist-js/issues/21\n labelRadius = options.donut ? radius : radius / 2;\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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].elem('path', {\n d: path.stringify()\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n\n // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","recursiveConvert","isNaN","hasOwnProperty","reversed","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","j","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","recursiveHighLow","findHigh","highLow","high","findLow","low","Number","MAX_VALUE","rho","num","gcd","p","q","f","x","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","y","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","attributes","parent","insertFirst","Element","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","joinedPath","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","smoothing","point","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisStepCount","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.8.2\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.8.2'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n // Rcursively 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(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) {\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n return +value;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = undefined;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray, options) {\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 findHigh = options.high === undefined,\n 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 instanceof Array) {\n for (var i = 0; i < data.length; i++) {\n recursiveHighLow(data[i]);\n }\n } else {\n if (findHigh && data > highLow.high) {\n highLow.high = data;\n }\n\n if (findLow && data < highLow.low) {\n highLow.low = data;\n }\n }\n }\n\n // Start to find highest and lowest number recursively\n recursiveHighLow(dataArray);\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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 }\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = 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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()];\n var projectedValues = data.map(axis.projectValue.bind(axis));\n var labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\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(axis.units.pos === 'x') {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n labelOffset.x = options.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(options.axisX.position === 'start') {\n labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 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(options.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10;\n } else {\n labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir],\n options.classNames[axisOptions.position]\n ], useForeignObject, eventEmitter);\n }\n });\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 * 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 });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n Chartist.Svg.Path.join = join;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, 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.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / this.bounds.range,\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 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 // 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 // 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 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 seriesGroups = [];\n var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var highLow = Chartist.getHighLow(normalizedData, options);\n\n var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n });\n\n var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger\n });\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\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 };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : 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 = seriesGroups[seriesIndex].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 'value': pathElement.data.value,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 group: seriesGroups[seriesIndex],\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(seriesOptions.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 seriesGroups = [];\n var data = Chartist.getDataArray(this.data, options.reverseData);\n var normalizedData = options.distributeSeries ? data.map(function(value) {\n return [value];\n }) : Chartist.normalizeDataArray(data, this.data.labels.length);\n var highLow;\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 if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(normalizedData, options);\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 labelAxisStepCount,\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 but stacked bars aren't, we need to use the one dimensional series array\n // length as step count for the label axis\n labelAxisStepCount = normalizedData.length;\n } else 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 set step\n // count to 1\n labelAxisStepCount = 1;\n } else {\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length\n // as the bars are normalized\n labelAxisStepCount = this.data.labels.length;\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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n onlyInteger: options.axisX.onlyInteger,\n referenceValue: 0\n });\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger,\n referenceValue: 0\n });\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength;\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 / normalizedData.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 / normalizedData[seriesIndex].length / 2;\n }\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[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 || 0, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].elem('path', {\n d: path.stringify()\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/dist/scss/chartist.scss b/dist/scss/chartist.scss index aaeb6953..fe68f886 100644 --- a/dist/scss/chartist.scss +++ b/dist/scss/chartist.scss @@ -62,6 +62,7 @@ color: $ct-text-color; font-size: $ct-text-size; line-height: $ct-text-line-height; + alignment-baseline: middle; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { diff --git a/package.json b/package.json index 72b5e94c..ff05ede8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.8.1", + "version": "0.8.2", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From baae4476f8013dfb5386a7061efc17cd207dc94e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 2 Jun 2015 22:16:30 +0200 Subject: [PATCH 260/593] doc: Added donut animation example --- site/data/pages/examples.yml | 10 ++++ site/examples/example-donut-animation.js | 55 +++++++++++++++++++ site/examples/example-simple-svg-animation.js | 8 +-- 3 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 site/examples/example-donut-animation.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 4f4f7301..a6d45f73 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -237,3 +237,13 @@ sections: id: simple-gauge-chart classes: ct-golden-section ct-negative-labels intro: This pie chart uses donut, startAngle and total to draw a gauge chart. + + - type: live-example + data: + title: Animating a Donut with Svg.animate + level: 4 + id: example-donut-animation + classes: ct-golden-section + intro: > + Although it'd be also possible to achieve this animation with CSS, with some minor suboptimal + things, here's an example of how to animate donut charts using Chartist.Svg.animate and SMIL. diff --git a/site/examples/example-donut-animation.js b/site/examples/example-donut-animation.js new file mode 100644 index 00000000..72f3501e --- /dev/null +++ b/site/examples/example-donut-animation.js @@ -0,0 +1,55 @@ +var chart = new Chartist.Pie('.ct-chart', { + series: [10, 20, 50, 20, 5, 50, 15], + labels: [1, 2, 3, 4, 5, 6, 7] +}, { + donut: true, + showLabel: false +}); + +chart.on('draw', function(data) { + if(data.type === 'slice') { + // Get the total path length in order to use for dash array animation + var pathLength = data.element._node.getTotalLength(); + + // Set a dasharray that matches the path length as prerequisite to animate dashoffset + data.element.attr({ + 'stroke-dasharray': pathLength + 'px ' + pathLength + 'px' + }); + + // Create animation definition while also assigning an ID to the animation for later sync usage + var animationDefinition = { + 'stroke-dashoffset': { + id: 'anim' + data.index, + dur: 1000, + from: -pathLength + 'px', + to: '0px', + easing: Chartist.Svg.Easing.easeOutQuint, + // We need to use `fill: 'freeze'` otherwise our animation will fall back to initial (not visible) + fill: 'freeze' + } + }; + + // If this was not the first slice, we need to time the animation so that it uses the end sync event of the previous animation + if(data.index !== 0) { + animationDefinition['stroke-dashoffset'].begin = 'anim' + (data.index - 1) + '.end'; + } + + // We need to set an initial value before the animation starts as we are not in guided mode which would do that for us + data.element.attr({ + 'stroke-dashoffset': -pathLength + 'px' + }); + + // We can't use guided mode as the animations need to rely on setting begin manually + // See http://gionkunz.github.io/chartist-js/api-documentation.html#chartistsvg-function-animate + data.element.animate(animationDefinition, false); + } +}); + +// For the sake of the example we update the chart every time it's created with a delay of 8 seconds +chart.on('created', function() { + if(window.__anim21278907124) { + clearTimeout(window.__anim21278907124); + window.__anim21278907124 = null; + } + window.__anim21278907124 = setTimeout(chart.update.bind(chart), 10000); +}); diff --git a/site/examples/example-simple-svg-animation.js b/site/examples/example-simple-svg-animation.js index 69a57816..97c7a7a1 100644 --- a/site/examples/example-simple-svg-animation.js +++ b/site/examples/example-simple-svg-animation.js @@ -54,10 +54,10 @@ chart.on('draw', function(data) { // For the sake of the example we update the chart every time it's created with a delay of 8 seconds chart.on('created', function() { - if(window.__exampleAnimateTimeout) { - clearTimeout(window.__exampleAnimateTimeout); - window.__exampleAnimateTimeout = null; + if(window.__anim0987432598723) { + clearTimeout(window.__anim0987432598723); + window.__anim0987432598723 = null; } - window.__exampleAnimateTimeout = setTimeout(chart.update.bind(chart), 8000); + window.__anim0987432598723 = setTimeout(chart.update.bind(chart), 8000); }); From b7ebb604bc4a7251d1aae649b23f80a164c7ac46 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 3 Jun 2015 00:38:24 +0200 Subject: [PATCH 261/593] Added better handling for area drawing with segmented paths, fixes #340 --- src/scripts/charts/line.js | 67 +++++++++++++++++++++++--------------- src/scripts/svg-path.js | 31 ++++++++++++++++-- test/spec/spec-svg.js | 26 +++++++++++++++ 3 files changed, 95 insertions(+), 29 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index e1d8647f..21279864 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -259,34 +259,49 @@ // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; - // Clone original path and splice our new area path to add the missing path elements to close the area shape - var areaPath = path.clone(); - // Modify line path and add missing elements for area - areaPath.position(0) - .remove(1) - .move(chartRect.x1, areaBaseProjected) - .line(pathCoordinates[0], pathCoordinates[1]) - .position(areaPath.pathElements.length) - .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); + // In order to form the area we'll first split the path by move commands so we can chunk it up into segments + path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { + // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area + return pathSegment.pathElements.length > 1; + }).map(function convertToArea(solidPathSegments) { + // Receiving the filtered solid path segments we can now convert those segments into fill areas + var firstElement = solidPathSegments.pathElements[0]; + var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; - // Create the new path for the area shape with the area class from the options - var area = seriesGroups[seriesIndex].elem('path', { - d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); + // Cloning the solid path segment with closing option and removing the first move command from the clone + // We then insert a new move that should start at the area base and draw a straight line up or down + // at the end of the path we add an additional straight line to the projected area base value + // As the closing option is set our path will be automatically closed + return solidPathSegments.clone(true) + .position(0) + .remove(1) + .move(firstElement.x, areaBaseProjected) + .line(firstElement.x, firstElement.y) + .position(solidPathSegments.pathElements.length + 1) + .line(lastElement.x, areaBaseProjected); - this.eventEmitter.emit('draw', { - type: 'area', - values: normalizedData[seriesIndex], - path: areaPath.clone(), - series: series, - seriesIndex: seriesIndex, - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: area - }); + }).forEach(function createArea(areaPath) { + // For each of our newly created area paths, we'll now create path elements by stringifying our path objects + // and adding the created DOM elements to the correct series group + var area = seriesGroups[seriesIndex].elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); + + // Emit an event for each area that was drawn + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[seriesIndex], + path: areaPath.clone(), + series: series, + seriesIndex: seriesIndex, + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], + element: area + }); + }.bind(this)); } }.bind(this)); diff --git a/src/scripts/svg-path.js b/src/scripts/svg-path.js index 366256b8..06e5e286 100644 --- a/src/scripts/svg-path.js +++ b/src/scripts/svg-path.js @@ -306,10 +306,11 @@ * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. * * @memberof Chartist.Svg.Path + * @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. * @return {Chartist.Svg.Path} */ - function clone() { - var c = new Chartist.Svg.Path(this.close); + function clone(close) { + var c = new Chartist.Svg.Path(close || this.close); c.pos = this.pos; c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { return Chartist.extend({}, pathElement); @@ -318,6 +319,29 @@ return c; } + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {String} command The command you'd like to use to split the path + * @return {Array} + */ + function splitByCommand(command) { + var split = [ + new Chartist.Svg.Path() + ]; + + this.pathElements.forEach(function(pathElement) { + if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) { + split.push(new Chartist.Svg.Path()); + } + + split[split.length - 1].pathElements.push(pathElement); + }); + + return split; + } + /** * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths. * @@ -352,7 +376,8 @@ transform: transform, parse: parse, stringify: stringify, - clone: clone + clone: clone, + splitByCommand: splitByCommand }); Chartist.Svg.Path.elementDescriptions = elementDescriptions; diff --git a/test/spec/spec-svg.js b/test/spec/spec-svg.js index b2cd5f60..f997242d 100644 --- a/test/spec/spec-svg.js +++ b/test/spec/spec-svg.js @@ -297,5 +297,31 @@ describe('Chartist SVG', function () { { command: 'C', x1: 5, y1: 100, x2: 7, y2: 100, x: 0, y: 0 } ]); }); + + it('should split correctly by move command', function () { + var paths = new Chartist.Svg.Path().parse('M0,0L0,0L0,0L0,0M0,0L0,0L0,0L0,0').splitByCommand('M'); + expect(paths).toHaveLength(2); + expect(paths[0].pathElements[0].command).toBe('M'); + expect(paths[0].pathElements).toHaveLength(4); + expect(paths[1].pathElements[0].command).toBe('M'); + expect(paths[1].pathElements).toHaveLength(4); + }); + + it('should split correctly by move command and tailing move element', function () { + var paths = new Chartist.Svg.Path().parse('M0,0L0,0L0,0L0,0M0,0L0,0L0,0L0,0M0,0').splitByCommand('M'); + expect(paths).toHaveLength(3); + expect(paths[2].pathElements[0].command).toBe('M'); + }); + + it('should split correctly by move command and leading other commands', function () { + var paths = new Chartist.Svg.Path().parse('L0,0C0,0,0,0,0,0M0,0L0,0L0,0L0,0M0,0L0,0L0,0L0,0').splitByCommand('M'); + expect(paths).toHaveLength(3); + expect(paths[0].pathElements).toHaveLength(2); + expect(paths[0].pathElements[0].command).toBe('L'); + expect(paths[0].pathElements[1].command).toBe('C'); + + expect(paths[1].pathElements).toHaveLength(4); + expect(paths[1].pathElements[0].command).toBe('M'); + }); }); }); From 0dabf391846f78e4aa63a5dc25508c96d3cc4d63 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 6 Jun 2015 19:00:10 +0200 Subject: [PATCH 262/593] Added more robust detach mechanism that takes async initialization into account --- src/scripts/base.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index 375079e7..12c66247 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -57,8 +57,15 @@ * @memberof Chartist.Base */ function detach() { - window.removeEventListener('resize', this.resizeListener); - this.optionsProvider.removeMediaQueryListeners(); + // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore + // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout + if(!this.initializeTimeoutId) { + window.removeEventListener('resize', this.resizeListener); + this.optionsProvider.removeMediaQueryListeners(); + } else { + window.clearTimeout(this.initializeTimeoutId); + } + return this; } From 4b0a7b732c1c40f804139f3dc5a1f1ec5dde67b4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 6 Jun 2015 19:34:46 +0200 Subject: [PATCH 263/593] Refactored initialization code, cleaned redundant code --- src/scripts/base.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/scripts/base.js b/src/scripts/base.js index 12c66247..1ca36a2a 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -157,14 +157,7 @@ if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { - if(this.container.__chartist__.initializeTimeoutId) { - // If the initializeTimeoutId is still set we can safely assume that the initialization function has not - // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach - window.clearTimeout(this.container.__chartist__.initializeTimeoutId); - } else { - // The timeout reference has already been reset which means we need to detach the old chart first - this.container.__chartist__.detach(); - } + this.container.__chartist__.detach(); } this.container.__chartist__ = this; From b598ea5f257ebb6f56ac922c88a0154661e3532b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 6 Jun 2015 19:35:17 +0200 Subject: [PATCH 264/593] doc: removed unecessary code from example code evaluator --- site/scripts/main.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/site/scripts/main.js b/site/scripts/main.js index df5a0c6f..38d8b823 100644 --- a/site/scripts/main.js +++ b/site/scripts/main.js @@ -12,9 +12,6 @@ function evalChartistCode(code, chartElement) { // Remove any declaration of $chart as we are passing $chart to our function eval modified = modified.replace(/var \$chart.+;/, ''); - if(chartElement.__chartist__) { - chartElement.__chartist__.detach(); - } var $chartElement = $(chartElement).empty(); try { From a760292a3f54072585ec6e6efbc0337371eafc3a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 7 Jun 2015 00:49:53 +0200 Subject: [PATCH 265/593] doc: Added more sophisticated documentation for styling --- .../colour-override-line-chart.css | 9 + site/code-snippets/custom-style-bar-chart.css | 11 ++ .../custom-style-donut-chart.css | 9 + .../code-snippets/custom-style-line-chart.css | 19 ++ site/code-snippets/custom-style-pie-chart.css | 9 + site/data/pages/getting-started.yml | 166 +++++++++++++++++- site/examples/example-dynamic-colours.js | 41 +++++ site/styles/_base.scss | 6 + 8 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 site/code-snippets/colour-override-line-chart.css create mode 100644 site/code-snippets/custom-style-bar-chart.css create mode 100644 site/code-snippets/custom-style-donut-chart.css create mode 100644 site/code-snippets/custom-style-line-chart.css create mode 100644 site/code-snippets/custom-style-pie-chart.css create mode 100644 site/examples/example-dynamic-colours.js diff --git a/site/code-snippets/colour-override-line-chart.css b/site/code-snippets/colour-override-line-chart.css new file mode 100644 index 00000000..62b45810 --- /dev/null +++ b/site/code-snippets/colour-override-line-chart.css @@ -0,0 +1,9 @@ +.ct-chart .ct-series.ct-series-a .ct-line, +.ct-chart .ct-series.ct-series-a .ct-point { + stroke: blue; +} + +.ct-chart .ct-series.ct-series-b .ct-line, +.ct-chart .ct-series.ct-series-b .ct-point { + stroke: green; +} diff --git a/site/code-snippets/custom-style-bar-chart.css b/site/code-snippets/custom-style-bar-chart.css new file mode 100644 index 00000000..ed526875 --- /dev/null +++ b/site/code-snippets/custom-style-bar-chart.css @@ -0,0 +1,11 @@ +/* Use this selector to override bar styles on bar charts. Bars are also strokes so you have maximum freedom in styling them. */ +.ct-chart-bar .ct-series.ct-series-a .ct-bar { + /* Colour of your bars */ + stroke: red; + /* The width of your bars */ + stroke-width: 20px; + /* Yes! Dashed bars! */ + stroke-dasharray: 20px; + /* Maybe you like round corners on your bars? */ + stroke-linecap: round; +} diff --git a/site/code-snippets/custom-style-donut-chart.css b/site/code-snippets/custom-style-donut-chart.css new file mode 100644 index 00000000..1ca99efe --- /dev/null +++ b/site/code-snippets/custom-style-donut-chart.css @@ -0,0 +1,9 @@ +/* Donut charts get built from Pie charts but with a fundametal difference in the drawing approach. The donut is drawn using arc strokes for maximum freedom in styling */ +.ct-chart-pie .ct-series.ct-series-a .ct-slice.ct-donut { + /* give the donut slice a custom colour */ + stroke: blue; + /* customize stroke width of the donut slices in CSS. Note that this property is already set in JavaScript and label positioning also relies on this. In the right situation though it can be very useful to style this property. You need to use !important to override the style attribute */ + stroke-width: 5px !important; + /* create modern looking rounded donut charts */ + stroke-linecap: round; +} diff --git a/site/code-snippets/custom-style-line-chart.css b/site/code-snippets/custom-style-line-chart.css new file mode 100644 index 00000000..4d42cd1c --- /dev/null +++ b/site/code-snippets/custom-style-line-chart.css @@ -0,0 +1,19 @@ +/* Use this selector to override the line style on a given series */ +.ct-chart-line .ct-series.ct-series-a .ct-line { + /* Set the colour of this series line */ + stroke: red; + /* Control the thikness of your lines */ + stroke-width: 5px; + /* Create a dashed line with a pattern */ + stroke-dasharray: 10px 20px; +} + +/* This selector overrides the points style on line charts. Points on line charts are actually just very short strokes. This allows you to customize even the point size in CSS */ +.ct-chart-line .ct-series.ct-series-a .ct-point { + /* Colour of your points */ + stroke: red; + /* Size of your points */ + stroke-width: 20px; + /* Make your points appear as squares */ + stroke-linecap: square; +} diff --git a/site/code-snippets/custom-style-pie-chart.css b/site/code-snippets/custom-style-pie-chart.css new file mode 100644 index 00000000..29a92b01 --- /dev/null +++ b/site/code-snippets/custom-style-pie-chart.css @@ -0,0 +1,9 @@ +/* Pie charts consist of solid slices where you can use this selector to override the default style. As the Pie chart is kind of a hybrid donut aswell, you need to distinguish with a :not pseudo class selector */ +.ct-chart-pie .ct-series.ct-series-a .ct-slice:not(.ct-donut) { + /* fill of the pie slieces */ + fill: hsl(120, 40%, 60%); + /* give your pie slices some outline or separate them visually by using the backrgound color here */ + stroke: white; + /* outline width */ + stroke-width: 4px; +} diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 16102c21..b3060887 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -124,7 +124,7 @@ sections: - type: code-snippet data: - id: default-Sass-settings + id: default-sass-settings button: Show default settings path: src/styles/settings/_chartist-settings.scss lang: scss @@ -403,6 +403,168 @@ sections: classes: ct-golden-section show-code-button: Show code + - title: Styling your chart + level: 3 + items: + - type: text + data: + text: > + You should always use the power of CSS to make your data pop into your visitors eyes. I know + I’m telling this over and over but it’s all about a clean separation of concerns. In this chapter + you’ll find some useful information on how to style your charts with CSS. + - type: sub-section + data: + title: Customizing the default CSS + level: 4 + items: + - type: text + data: + text: > + Chartist comes with a highly customizable Sass file that allows you to customize all sorts of + appearance relevant things on your charts including colours used for series, line styles, + thickness and other properties. If you have the advantage of having a Sass build process at + your disposal, I highly recommend you to use the Sass version of Chartist instead of the + already prebuilt CSS. For more information on how to use the Sass version + please check out the Sass way of Chartist. + + - type: text + data: + text: > + Chartist generates predefined classes for series by default. Those class names are alpha + numerated and always start with ct-series-a, where the letter a will be iterated + with each series count (a, b, c, d etc.). To address a specific series in styling, you’ll + need to create some styles for the corresponding series class name. + + - type: text + data: + text: > + Here is a list of selectors from the different chart types with some comments to explain what + properties can be used to influence the visual style of your charts. + + - type: sub-section + data: + title: Line chart + level: 5 + items: + - type: code-snippet + data: + id: custom-style-line-chart + lang: css + + - type: sub-section + data: + title: Bar chart + level: 5 + items: + - type: code-snippet + data: + id: custom-style-bar-chart + lang: css + + - type: sub-section + data: + title: Pie chart + level: 5 + items: + - type: code-snippet + data: + id: custom-style-pie-chart + lang: css + + - type: sub-section + data: + title: Donut chart + level: 5 + items: + - type: code-snippet + data: + id: custom-style-donut-chart + lang: css + + - type: sub-section + data: + title: Colour up your charts + level: 4 + items: + - type: text + data: + text: > + Colour is a core attribute of appearance and as you already know, we believe in strong + separation of concerns in web development. Therefore, Chartist does not include any options + within the JavaScript API to control colour of your charts. + - type: text + data: + text: > + This might first seem very inconvenient, but you’ll agree that it’s the right choice once you + need to change some colours in your web project where you’d need to go through some nasty + find-and-replace adventures in your JavaScript files to fix some colour mismatches. + - type: text + data: + text: > + The prebuilt CSS version of Chartist ships with 15 default colours that will be applied to your + chart series elements. If you just want to override some of these colours I recommend you use + the information + found in how to customize the default CSS of Chartist. + - type: text + data: + text: > + The following example illustrates how you’d override the colours of your line chart line and + point elements, within the two first sieries (ct-series-a and ct-series-b). + - type: code-snippet + data: + id: colour-override-line-chart + lang: css + + - type: text + data: + text: > + Note that on SVG elements there are two CSS properties for colourization. For strokes you + should use the stroke property and assign a CSS colour value. For fill areas you + can use the fill property. More information can be found in the above topics. + + - type: sub-section + data: + title: Dynamic colouring + level: 5 + items: + - type: text + data: + text: > + Often, predefined classes which can be used to colour your charts are fine but sometimes + CSS is not flexible enough to control all facets of dynamic appearance. While we could + build semantic classes like level1, level2, level3 and so on, we could then assign a + class dynamically, but still we’d need to rely on discrete values defined in CSS. One + lack of CSS today is that it does not incorporate dynamic values like mouse position + or placeholder variables that can be linked to JavaScript. + - type: text + data: + text: > + So, how do you go about your heat map chart or dynamically calculated line chart + strokes based on your data? + - type: text + data: + text: > + Chartist offers you a powerful tool for such kind of chart manipulations. The intrusive + event pipeline of Chartist allows you to hook into a draw event that allows + you to modify all your charts elements on the go while they’re drawn. + - type: text + data: + text: > + The following live code example shows you how to make a dynamically coloured chart + based on some data. Please go ahead and play around with the example, that’s what live + coding is for! For more information on how to use the Chartist.Svg API, + please check + the API documentation. + - type: live-example + data: + title: Using draw events to modify chart elements + level: 5 + id: example-dynamic-colours + classes: ct-golden-section + intro: > + By using the intrusive event pipeline of Chartist, you can easily change the behaviour of your + charts in a consistent and convenient way. + - title: Advanced level: 3 items: @@ -416,7 +578,7 @@ sections: - type: sub-section data: - title: Adding behavior to your charts + title: Adding behaviour to your charts level: 4 items: - type: text diff --git a/site/examples/example-dynamic-colours.js b/site/examples/example-dynamic-colours.js new file mode 100644 index 00000000..135442e9 --- /dev/null +++ b/site/examples/example-dynamic-colours.js @@ -0,0 +1,41 @@ +var count = 45; +var max = 100; + +// Utility function to produce an empty array without holes +function times(n) { + return Array.apply(null, new Array(n)); +} + +// Utility function to be usen in Array.map to multiply a value +function multiplyFactory(multiplier) { + return function(num) { + return num * multiplier; + }; +} + +// Creating a bar chart with no labels and a series array with one series. For the series we generate random data with `count` elements and random data ranging from 0 to `max`. +var chart = new Chartist.Bar('.ct-chart', { + labels: times(count), + series: [ + times(count).map(Math.random).map(multiplyFactory(max)) + ] +}, { + axisX: { + showLabel: false + }, + axisY: { + onlyInteger: true + } +}); + +// This is the bit we are actually interested in. By registering a callback for `draw` events, we can actually intercept the drawing process of each element on the chart. +chart.on('draw', function(context) { + // First we want to make sure that only do something when the draw event is for bars. Draw events do get fired for labels and grids too. + if(context.type === 'bar') { + // With the Chartist.Svg API we can easily set an attribute on our bar that just got drawn + context.element.attr({ + // Now we set the style attribute on our bar to override the default color of the bar. By using a HSL colour we can easily set the hue of the colour dynamically while keeping the same saturation and lightness. From the context we can also get the current value of the bar. We use that value to calculate a hue between 0 and 100 degree. This will make our bars appear green when close to the maximum and red when close to zero. + style: 'stroke: hsl(' + Math.floor(context.value / max * 100) + ', 50%, 50%);' + }); + } +}); diff --git a/site/styles/_base.scss b/site/styles/_base.scss index 0fe3a99d..e5bd390c 100644 --- a/site/styles/_base.scss +++ b/site/styles/_base.scss @@ -122,3 +122,9 @@ table { padding: 0.8em 1em; } } + +p > code { + background-color: rgba(255, 255, 255, 0.3); + padding: 0.1em 0.2em; + border-radius: 2px; +} From 7e524e45220e461f58b52b9fef96a7e934c4d2f5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 7 Jun 2015 10:32:48 +0200 Subject: [PATCH 266/593] Greatly reduced CSS selector complexity and split slice into slice-pie and slice-donut --- .../example-bar-with-circle-modify-drawing.js | 2 +- src/scripts/charts/pie.js | 11 ++++--- src/styles/chartist.scss | 31 ++++++++----------- src/styles/settings/_chartist-settings.scss | 5 +-- test/spec/spec-pie-chart.js | 2 +- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/site/examples/example-bar-with-circle-modify-drawing.js b/site/examples/example-bar-with-circle-modify-drawing.js index a5b71c4b..a4617451 100644 --- a/site/examples/example-bar-with-circle-modify-drawing.js +++ b/site/examples/example-bar-with-circle-modify-drawing.js @@ -23,6 +23,6 @@ chart.on('draw', function(data) { cx: data.x2, cy: data.y2, r: Math.abs(data.value) * 2 + 5 - }, 'ct-slice')); + }, 'ct-slice-pie')); } }); diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 477ba965..f33295e9 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -21,10 +21,11 @@ chartPadding: 5, // Override the class names that are used to generate the SVG structure of the chart classNames: { - chart: 'ct-chart-pie', + chartPie: 'ct-chart-pie', + chartDonut: 'ct-chart-donut', series: 'ct-series', - slice: 'ct-slice', - donut: 'ct-donut', + slicePie: 'ct-slice-pie', + sliceDonut: 'ct-slice-donut', label: 'ct-label' }, // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. @@ -86,7 +87,7 @@ dataArray = Chartist.getDataArray(this.data, options.reverseData); // Create SVG.js draw - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie); // Calculate charting rect chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); // Get biggest circle radius possible within chartRect @@ -168,7 +169,7 @@ // If this is a donut chart we add the donut class, otherwise just a regular slice var pathElement = seriesGroups[i].elem('path', { d: path.stringify() - }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); + }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie); // Adding the pie series value to the path pathElement.attr({ diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index fe68f886..0f19ba05 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -62,7 +62,6 @@ color: $ct-text-color; font-size: $ct-text-size; line-height: $ct-text-line-height; - alignment-baseline: middle; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { @@ -104,11 +103,11 @@ } @mixin ct-chart-series-color($color) { - .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice}.#{$ct-class-donut} { + .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice-donut} { stroke: $color; } - .#{$ct-class-slice}:not(.#{$ct-class-donut}), .#{$ct-class-area} { + .#{$ct-class-slice-pie}, .#{$ct-class-area} { fill: $color; } } @@ -205,32 +204,28 @@ @include ct-chart-bar($ct-bar-width); } - .#{$ct-class-slice}.#{$ct-class-donut} { + .#{$ct-class-slice-donut} { @include ct-chart-donut($ct-donut-width); } @if $ct-include-colored-series { - .#{$ct-class-series} { - @for $i from 0 to length($ct-series-names) { - &.#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { - $color: nth($ct-series-colors, $i + 1); + @for $i from 0 to length($ct-series-names) { + .#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { + $color: nth($ct-series-colors, $i + 1); - @include ct-chart-series-color($color); - } + @include ct-chart-series-color($color); } } } } @if $ct-include-classes { - .#{$ct-class-chart} { - @include ct-chart(); - - @if $ct-include-alternative-responsive-containers { - @for $i from 0 to length($ct-scales-names) { - &.#{nth($ct-scales-names, $i + 1)} { - @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); - } + @include ct-chart(); + + @if $ct-include-alternative-responsive-containers { + @for $i from 0 to length($ct-scales-names) { + .#{nth($ct-scales-names, $i + 1)} { + @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); } } } diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss index af242f49..21b92c13 100644 --- a/src/styles/settings/_chartist-settings.scss +++ b/src/styles/settings/_chartist-settings.scss @@ -8,14 +8,15 @@ $ct-class-chart-line: ct-chart-line !default; $ct-class-chart-bar: ct-chart-bar !default; $ct-class-horizontal-bars: ct-horizontal-bars !default; $ct-class-chart-pie: ct-chart-pie !default; +$ct-class-chart-donut: ct-chart-donut !default; $ct-class-label: ct-label !default; $ct-class-series: ct-series !default; $ct-class-line: ct-line !default; $ct-class-point: ct-point !default; $ct-class-area: ct-area !default; $ct-class-bar: ct-bar !default; -$ct-class-slice: ct-slice !default; -$ct-class-donut: ct-donut !default; +$ct-class-slice-pie: ct-slice-pie !default; +$ct-class-slice-donut: ct-slice-donut !default; $ct-class-grid: ct-grid !default; $ct-class-vertical: ct-vertical !default; $ct-class-horizontal: ct-horizontal !default; diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index db8a1932..834013ea 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -28,7 +28,7 @@ describe('Pie chart tests', function() { var chart = new Chartist.Pie('.ct-chart', data); chart.on('created', function() { - expect(Chartist.deserialize($('.ct-slice').eq(1).attr('ct:meta'))).toEqual(meta); + expect(Chartist.deserialize($('.ct-slice-pie').eq(1).attr('ct:meta'))).toEqual(meta); done(); }); }); From 2ae81089f353c15081ebcbcaa295f0e970d21626 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 7 Jun 2015 11:49:18 +0200 Subject: [PATCH 267/593] doc: Fixed documentation for CSS selectors with new specificity --- .../colour-override-line-chart.css | 8 +-- site/code-snippets/custom-style-bar-chart.css | 2 +- .../custom-style-donut-chart.css | 4 +- .../code-snippets/custom-style-line-chart.css | 4 +- site/code-snippets/custom-style-pie-chart.css | 6 +- .../example-line-months-interpolation.js | 6 +- site/styles/_example-charts.scss | 62 +++++++++---------- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/site/code-snippets/colour-override-line-chart.css b/site/code-snippets/colour-override-line-chart.css index 62b45810..54306316 100644 --- a/site/code-snippets/colour-override-line-chart.css +++ b/site/code-snippets/colour-override-line-chart.css @@ -1,9 +1,9 @@ -.ct-chart .ct-series.ct-series-a .ct-line, -.ct-chart .ct-series.ct-series-a .ct-point { +.ct-series-a .ct-line, +.ct-series-a .ct-point { stroke: blue; } -.ct-chart .ct-series.ct-series-b .ct-line, -.ct-chart .ct-series.ct-series-b .ct-point { +.ct-series-b .ct-line, +.ct-series-b .ct-point { stroke: green; } diff --git a/site/code-snippets/custom-style-bar-chart.css b/site/code-snippets/custom-style-bar-chart.css index ed526875..9c6809ad 100644 --- a/site/code-snippets/custom-style-bar-chart.css +++ b/site/code-snippets/custom-style-bar-chart.css @@ -1,5 +1,5 @@ /* Use this selector to override bar styles on bar charts. Bars are also strokes so you have maximum freedom in styling them. */ -.ct-chart-bar .ct-series.ct-series-a .ct-bar { +.ct-series-a .ct-bar { /* Colour of your bars */ stroke: red; /* The width of your bars */ diff --git a/site/code-snippets/custom-style-donut-chart.css b/site/code-snippets/custom-style-donut-chart.css index 1ca99efe..a96c124c 100644 --- a/site/code-snippets/custom-style-donut-chart.css +++ b/site/code-snippets/custom-style-donut-chart.css @@ -1,5 +1,5 @@ -/* Donut charts get built from Pie charts but with a fundametal difference in the drawing approach. The donut is drawn using arc strokes for maximum freedom in styling */ -.ct-chart-pie .ct-series.ct-series-a .ct-slice.ct-donut { +/* Donut charts get built from Pie charts but with a fundamentally difference in the drawing approach. The donut is drawn using arc strokes for maximum freedom in styling */ +.ct-series-a .ct-slice-donut { /* give the donut slice a custom colour */ stroke: blue; /* customize stroke width of the donut slices in CSS. Note that this property is already set in JavaScript and label positioning also relies on this. In the right situation though it can be very useful to style this property. You need to use !important to override the style attribute */ diff --git a/site/code-snippets/custom-style-line-chart.css b/site/code-snippets/custom-style-line-chart.css index 4d42cd1c..82bdaf63 100644 --- a/site/code-snippets/custom-style-line-chart.css +++ b/site/code-snippets/custom-style-line-chart.css @@ -1,5 +1,5 @@ /* Use this selector to override the line style on a given series */ -.ct-chart-line .ct-series.ct-series-a .ct-line { +.ct-series-a .ct-line { /* Set the colour of this series line */ stroke: red; /* Control the thikness of your lines */ @@ -9,7 +9,7 @@ } /* This selector overrides the points style on line charts. Points on line charts are actually just very short strokes. This allows you to customize even the point size in CSS */ -.ct-chart-line .ct-series.ct-series-a .ct-point { +.ct-series-a .ct-point { /* Colour of your points */ stroke: red; /* Size of your points */ diff --git a/site/code-snippets/custom-style-pie-chart.css b/site/code-snippets/custom-style-pie-chart.css index 29a92b01..52c30cc1 100644 --- a/site/code-snippets/custom-style-pie-chart.css +++ b/site/code-snippets/custom-style-pie-chart.css @@ -1,8 +1,8 @@ -/* Pie charts consist of solid slices where you can use this selector to override the default style. As the Pie chart is kind of a hybrid donut aswell, you need to distinguish with a :not pseudo class selector */ -.ct-chart-pie .ct-series.ct-series-a .ct-slice:not(.ct-donut) { +/* Pie charts consist of solid slices where you can use this selector to override the default style. */ +.ct-series-a .ct-slice-pie { /* fill of the pie slieces */ fill: hsl(120, 40%, 60%); - /* give your pie slices some outline or separate them visually by using the backrgound color here */ + /* give your pie slices some outline or separate them visually by using the background color here */ stroke: white; /* outline width */ stroke-width: 4px; diff --git a/site/examples/example-line-months-interpolation.js b/site/examples/example-line-months-interpolation.js index 3c053bd6..37538fed 100644 --- a/site/examples/example-line-months-interpolation.js +++ b/site/examples/example-line-months-interpolation.js @@ -25,4 +25,8 @@ var responsiveOptions = [ ] ]; -new Chartist.Line('.ct-chart', data, null, responsiveOptions); \ No newline at end of file +new Chartist.Line('.ct-chart', data, { + chartPadding: { + top: 30 + } +}, responsiveOptions); diff --git a/site/styles/_example-charts.scss b/site/styles/_example-charts.scss index 63fa9a9f..f16dae31 100644 --- a/site/styles/_example-charts.scss +++ b/site/styles/_example-charts.scss @@ -1,16 +1,14 @@ #chartist-guy #chart-canvas { @include ct-chart($ct-text-color: darken($color-white, 50%), $ct-grid-color: darken($color-white, 20%)); - .ct-series { - &.ct-series-a { - .ct-point { - @include ct-chart-point($ct-point-shape: square, $ct-point-size: 8px); - } + .ct-series-a { + .ct-point { + @include ct-chart-point($ct-point-shape: square, $ct-point-size: 8px); + } - .ct-line { - @include ct-chart-line($ct-line-dasharray: 5px); - @include animation(dashoffset, 1s linear infinite); - } + .ct-line { + @include ct-chart-line($ct-line-dasharray: 5px); + @include animation(dashoffset, 1s linear infinite); } } } @@ -18,36 +16,34 @@ #example-line-months-interpolation { @include ct-chart($ct-text-color: lighten($color-gray, 30%), $ct-grid-color: lighten($color-gray, 5%), $ct-grid-dasharray: 3px); - .ct-series { - &.ct-series-a { - .ct-point { - @include ct-chart-point($ct-point-shape: square); - } + .ct-series-a { + .ct-point { + @include ct-chart-point($ct-point-shape: square); + } - .ct-line { - @include ct-chart-line($ct-line-width: 4px, $ct-line-dasharray: 5px); - @include animation(dashoffset, 1s linear infinite); - } + .ct-line { + @include ct-chart-line($ct-line-width: 4px, $ct-line-dasharray: 5px); + @include animation(dashoffset, 1s linear infinite); } + } - &.ct-series-b { - .ct-point { - @include animation(bouncing-stroke, 0.5s ease infinite); - } + .ct-series-b { + .ct-point { + @include animation(bouncing-stroke, 0.5s ease infinite); + } - .ct-line { - @include ct-chart-line($ct-line-width: 3px); - } + .ct-line { + @include ct-chart-line($ct-line-width: 3px); } + } - &.ct-series-c { - .ct-point { - @include animation(exploding-stroke, 1s ease-out infinite); - } + .ct-series-c { + .ct-point { + @include animation(exploding-stroke, 1s ease-out infinite); + } - .ct-line { - @include ct-chart-line($ct-line-width: 2px, $ct-line-dasharray: 40px 3px); - } + .ct-line { + @include ct-chart-line($ct-line-width: 2px, $ct-line-dasharray: 40px 3px); } } } @@ -56,4 +52,4 @@ .ct-point { @include ct-chart-point($ct-point-size: 20px); } -} \ No newline at end of file +} From 17500f3906e88cb6f9e2de89eac658d8bc26ec40 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 7 Jun 2015 12:00:10 +0200 Subject: [PATCH 268/593] Added multiply and add map helper function and simplified example --- site/examples/example-dynamic-colours.js | 16 ++------------- src/scripts/core.js | 26 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/site/examples/example-dynamic-colours.js b/site/examples/example-dynamic-colours.js index 135442e9..24230627 100644 --- a/site/examples/example-dynamic-colours.js +++ b/site/examples/example-dynamic-colours.js @@ -1,23 +1,11 @@ var count = 45; var max = 100; -// Utility function to produce an empty array without holes -function times(n) { - return Array.apply(null, new Array(n)); -} - -// Utility function to be usen in Array.map to multiply a value -function multiplyFactory(multiplier) { - return function(num) { - return num * multiplier; - }; -} - // Creating a bar chart with no labels and a series array with one series. For the series we generate random data with `count` elements and random data ranging from 0 to `max`. var chart = new Chartist.Bar('.ct-chart', { - labels: times(count), + labels: Chartist.times(count), series: [ - times(count).map(Math.random).map(multiplyFactory(max)) + Chartist.times(count).map(Math.random).map(Chartist.mapMultiply(max)) ] }, { axisX: { diff --git a/src/scripts/core.js b/src/scripts/core.js index e8c91833..7dc5ba62 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -136,6 +136,32 @@ var Chartist = { return previous + (current ? current : 0); }; + /** + * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor. + * + * @memberof Chartist.Core + * @param {Number} factor + * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array + */ + Chartist.mapMultiply = function(factor) { + return function(num) { + return num * factor; + }; + }; + + /** + * Add helper to be used in `Array.map` for adding a addend to each value of an array. + * + * @memberof Chartist.Core + * @param {Number} addend + * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array + */ + Chartist.mapAdd = function(addend) { + return function(num) { + return num + addend; + }; + }; + /** * 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). * From e27d6f4556f35d09cad5207b7cadf3888a8ec618 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 7 Jun 2015 12:03:42 +0200 Subject: [PATCH 269/593] Version bump to 0.8.3 --- CHANGELOG.md | 7 + bower.json | 2 +- dist/chartist.js | 161 +++++++++++++++------ dist/chartist.min.css | 2 +- dist/chartist.min.js | 6 +- dist/chartist.min.js.map | 2 +- dist/scss/chartist.scss | 31 ++-- dist/scss/settings/_chartist-settings.scss | 5 +- package.json | 2 +- 9 files changed, 144 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1af02ac8..dcd89441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v0.8.3 - 07 Jun 2015 +-------------------- +- Greatly reduced CSS selector complexity and split slice into slice-pie and slice-donut +- Added more robust detach mechanism that takes async initialization into account +- Added better handling for area drawing with segmented paths, fixes #340 +- Documentation: Added getting started guide for styling charts + v0.8.2 - 02 Jun 2015 -------------------- - Fixed broken release 0.8.1 diff --git a/bower.json b/bower.json index fa81a6a5..0abfd55b 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.8.2", + "version": "0.8.3", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 7d6a4cd1..4ba8c3bd 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.8.2 +/* Chartist.js 0.8.3 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.8.2' + version: '0.8.3' }; (function (window, document, Chartist) { @@ -157,6 +157,32 @@ var Chartist = { return previous + (current ? current : 0); }; + /** + * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor. + * + * @memberof Chartist.Core + * @param {Number} factor + * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array + */ + Chartist.mapMultiply = function(factor) { + return function(num) { + return num * factor; + }; + }; + + /** + * Add helper to be used in `Array.map` for adding a addend to each value of an array. + * + * @memberof Chartist.Core + * @param {Number} addend + * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array + */ + Chartist.mapAdd = function(addend) { + return function(num) { + return num + addend; + }; + }; + /** * 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). * @@ -1501,8 +1527,15 @@ var Chartist = { * @memberof Chartist.Base */ function detach() { - window.removeEventListener('resize', this.resizeListener); - this.optionsProvider.removeMediaQueryListeners(); + // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore + // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout + if(!this.initializeTimeoutId) { + window.removeEventListener('resize', this.resizeListener); + this.optionsProvider.removeMediaQueryListeners(); + } else { + window.clearTimeout(this.initializeTimeoutId); + } + return this; } @@ -1594,14 +1627,7 @@ var Chartist = { if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { - if(this.container.__chartist__.initializeTimeoutId) { - // If the initializeTimeoutId is still set we can safely assume that the initialization function has not - // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach - window.clearTimeout(this.container.__chartist__.initializeTimeoutId); - } else { - // The timeout reference has already been reset which means we need to detach the old chart first - this.container.__chartist__.detach(); - } + this.container.__chartist__.detach(); } this.container.__chartist__ = this; @@ -2553,10 +2579,11 @@ var Chartist = { * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. * * @memberof Chartist.Svg.Path + * @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. * @return {Chartist.Svg.Path} */ - function clone() { - var c = new Chartist.Svg.Path(this.close); + function clone(close) { + var c = new Chartist.Svg.Path(close || this.close); c.pos = this.pos; c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { return Chartist.extend({}, pathElement); @@ -2565,6 +2592,29 @@ var Chartist = { return c; } + /** + * 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. + * + * @memberof Chartist.Svg.Path + * @param {String} command The command you'd like to use to split the path + * @return {Array} + */ + function splitByCommand(command) { + var split = [ + new Chartist.Svg.Path() + ]; + + this.pathElements.forEach(function(pathElement) { + if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) { + split.push(new Chartist.Svg.Path()); + } + + split[split.length - 1].pathElements.push(pathElement); + }); + + return split; + } + /** * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths. * @@ -2599,7 +2649,8 @@ var Chartist = { transform: transform, parse: parse, stringify: stringify, - clone: clone + clone: clone, + splitByCommand: splitByCommand }); Chartist.Svg.Path.elementDescriptions = elementDescriptions; @@ -2975,34 +3026,49 @@ var Chartist = { // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; - // Clone original path and splice our new area path to add the missing path elements to close the area shape - var areaPath = path.clone(); - // Modify line path and add missing elements for area - areaPath.position(0) - .remove(1) - .move(chartRect.x1, areaBaseProjected) - .line(pathCoordinates[0], pathCoordinates[1]) - .position(areaPath.pathElements.length) - .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected); - - // Create the new path for the area shape with the area class from the options - var area = seriesGroups[seriesIndex].elem('path', { - d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); + // In order to form the area we'll first split the path by move commands so we can chunk it up into segments + path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { + // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area + return pathSegment.pathElements.length > 1; + }).map(function convertToArea(solidPathSegments) { + // Receiving the filtered solid path segments we can now convert those segments into fill areas + var firstElement = solidPathSegments.pathElements[0]; + var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; + + // Cloning the solid path segment with closing option and removing the first move command from the clone + // We then insert a new move that should start at the area base and draw a straight line up or down + // at the end of the path we add an additional straight line to the projected area base value + // As the closing option is set our path will be automatically closed + return solidPathSegments.clone(true) + .position(0) + .remove(1) + .move(firstElement.x, areaBaseProjected) + .line(firstElement.x, firstElement.y) + .position(solidPathSegments.pathElements.length + 1) + .line(lastElement.x, areaBaseProjected); + + }).forEach(function createArea(areaPath) { + // For each of our newly created area paths, we'll now create path elements by stringifying our path objects + // and adding the created DOM elements to the correct series group + var area = seriesGroups[seriesIndex].elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true).attr({ + 'values': normalizedData[seriesIndex] + }, Chartist.xmlNs.uri); - this.eventEmitter.emit('draw', { - type: 'area', - values: normalizedData[seriesIndex], - path: areaPath.clone(), - series: series, - seriesIndex: seriesIndex, - chartRect: chartRect, - index: seriesIndex, - group: seriesGroups[seriesIndex], - element: area - }); + // Emit an event for each area that was drawn + this.eventEmitter.emit('draw', { + type: 'area', + values: normalizedData[seriesIndex], + path: areaPath.clone(), + series: series, + seriesIndex: seriesIndex, + chartRect: chartRect, + index: seriesIndex, + group: seriesGroups[seriesIndex], + element: area + }); + }.bind(this)); } }.bind(this)); @@ -3522,10 +3588,11 @@ var Chartist = { chartPadding: 5, // Override the class names that are used to generate the SVG structure of the chart classNames: { - chart: 'ct-chart-pie', + chartPie: 'ct-chart-pie', + chartDonut: 'ct-chart-donut', series: 'ct-series', - slice: 'ct-slice', - donut: 'ct-donut', + slicePie: 'ct-slice-pie', + sliceDonut: 'ct-slice-donut', label: 'ct-label' }, // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. @@ -3587,7 +3654,7 @@ var Chartist = { dataArray = Chartist.getDataArray(this.data, options.reverseData); // Create SVG.js draw - this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie); // Calculate charting rect chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); // Get biggest circle radius possible within chartRect @@ -3669,7 +3736,7 @@ var Chartist = { // If this is a donut chart we add the donut class, otherwise just a regular slice var pathElement = seriesGroups[i].elem('path', { d: path.stringify() - }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : '')); + }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie); // Adding the pie series value to the path pathElement.attr({ diff --git a/dist/chartist.min.css b/dist/chartist.min.css index 0690662b..f348f0ae 100644 --- a/dist/chartist.min.css +++ b/dist/chartist.min.css @@ -1 +1 @@ -.ct-chart.ct-double-octave:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-second:after,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-third:after,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-third:after,.ct-chart.ct-octave:after,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-square:after{content:"";clear:both}.ct-chart.ct-double-octave:after,.ct-chart.ct-double-octave:before,.ct-chart.ct-golden-section:after,.ct-chart.ct-major-eleventh:after,.ct-chart.ct-major-eleventh:before,.ct-chart.ct-major-second:after,.ct-chart.ct-major-second:before,.ct-chart.ct-major-seventh:after,.ct-chart.ct-major-seventh:before,.ct-chart.ct-major-sixth:after,.ct-chart.ct-major-sixth:before,.ct-chart.ct-major-tenth:after,.ct-chart.ct-major-tenth:before,.ct-chart.ct-major-third:after,.ct-chart.ct-major-third:before,.ct-chart.ct-major-twelfth:after,.ct-chart.ct-major-twelfth:before,.ct-chart.ct-minor-second:after,.ct-chart.ct-minor-second:before,.ct-chart.ct-minor-seventh:after,.ct-chart.ct-minor-seventh:before,.ct-chart.ct-minor-sixth:after,.ct-chart.ct-minor-sixth:before,.ct-chart.ct-minor-third:after,.ct-chart.ct-minor-third:before,.ct-chart.ct-octave:after,.ct-chart.ct-octave:before,.ct-chart.ct-perfect-fifth:after,.ct-chart.ct-perfect-fifth:before,.ct-chart.ct-perfect-fourth:after,.ct-chart.ct-perfect-fourth:before,.ct-chart.ct-square:after,.ct-chart.ct-square:before{content:""}.ct-chart .ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1;alignment-baseline:middle}.ct-chart .ct-chart-bar .ct-label,.ct-chart .ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart .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 .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 .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-chart .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 .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 .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 .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 .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 .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 .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-chart .ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-chart .ct-point{stroke-width:10px;stroke-linecap:round}.ct-chart .ct-line{fill:none;stroke-width:4px}.ct-chart .ct-area{stroke:none;fill-opacity:.1}.ct-chart .ct-bar{fill:none;stroke-width:10px}.ct-chart .ct-slice.ct-donut{fill:none;stroke-width:60px}.ct-chart .ct-series.ct-series-a .ct-bar,.ct-chart .ct-series.ct-series-a .ct-line,.ct-chart .ct-series.ct-series-a .ct-point,.ct-chart .ct-series.ct-series-a .ct-slice.ct-donut{stroke:#d70206}.ct-chart .ct-series.ct-series-a .ct-area,.ct-chart .ct-series.ct-series-a .ct-slice:not(.ct-donut){fill:#d70206}.ct-chart .ct-series.ct-series-b .ct-bar,.ct-chart .ct-series.ct-series-b .ct-line,.ct-chart .ct-series.ct-series-b .ct-point,.ct-chart .ct-series.ct-series-b .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-b .ct-area,.ct-chart .ct-series.ct-series-b .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-c .ct-bar,.ct-chart .ct-series.ct-series-c .ct-line,.ct-chart .ct-series.ct-series-c .ct-point,.ct-chart .ct-series.ct-series-c .ct-slice.ct-donut{stroke:#f4c63d}.ct-chart .ct-series.ct-series-c .ct-area,.ct-chart .ct-series.ct-series-c .ct-slice:not(.ct-donut){fill:#f4c63d}.ct-chart .ct-series.ct-series-d .ct-bar,.ct-chart .ct-series.ct-series-d .ct-line,.ct-chart .ct-series.ct-series-d .ct-point,.ct-chart .ct-series.ct-series-d .ct-slice.ct-donut{stroke:#d17905}.ct-chart .ct-series.ct-series-d .ct-area,.ct-chart .ct-series.ct-series-d .ct-slice:not(.ct-donut){fill:#d17905}.ct-chart .ct-series.ct-series-e .ct-bar,.ct-chart .ct-series.ct-series-e .ct-line,.ct-chart .ct-series.ct-series-e .ct-point,.ct-chart .ct-series.ct-series-e .ct-slice.ct-donut{stroke:#453d3f}.ct-chart .ct-series.ct-series-e .ct-area,.ct-chart .ct-series.ct-series-e .ct-slice:not(.ct-donut){fill:#453d3f}.ct-chart .ct-series.ct-series-f .ct-bar,.ct-chart .ct-series.ct-series-f .ct-line,.ct-chart .ct-series.ct-series-f .ct-point,.ct-chart .ct-series.ct-series-f .ct-slice.ct-donut{stroke:#59922b}.ct-chart .ct-series.ct-series-f .ct-area,.ct-chart .ct-series.ct-series-f .ct-slice:not(.ct-donut){fill:#59922b}.ct-chart .ct-series.ct-series-g .ct-bar,.ct-chart .ct-series.ct-series-g .ct-line,.ct-chart .ct-series.ct-series-g .ct-point,.ct-chart .ct-series.ct-series-g .ct-slice.ct-donut{stroke:#0544d3}.ct-chart .ct-series.ct-series-g .ct-area,.ct-chart .ct-series.ct-series-g .ct-slice:not(.ct-donut){fill:#0544d3}.ct-chart .ct-series.ct-series-h .ct-bar,.ct-chart .ct-series.ct-series-h .ct-line,.ct-chart .ct-series.ct-series-h .ct-point,.ct-chart .ct-series.ct-series-h .ct-slice.ct-donut{stroke:#6b0392}.ct-chart .ct-series.ct-series-h .ct-area,.ct-chart .ct-series.ct-series-h .ct-slice:not(.ct-donut){fill:#6b0392}.ct-chart .ct-series.ct-series-i .ct-bar,.ct-chart .ct-series.ct-series-i .ct-line,.ct-chart .ct-series.ct-series-i .ct-point,.ct-chart .ct-series.ct-series-i .ct-slice.ct-donut{stroke:#f05b4f}.ct-chart .ct-series.ct-series-i .ct-area,.ct-chart .ct-series.ct-series-i .ct-slice:not(.ct-donut){fill:#f05b4f}.ct-chart .ct-series.ct-series-j .ct-bar,.ct-chart .ct-series.ct-series-j .ct-line,.ct-chart .ct-series.ct-series-j .ct-point,.ct-chart .ct-series.ct-series-j .ct-slice.ct-donut{stroke:#dda458}.ct-chart .ct-series.ct-series-j .ct-area,.ct-chart .ct-series.ct-series-j .ct-slice:not(.ct-donut){fill:#dda458}.ct-chart .ct-series.ct-series-k .ct-bar,.ct-chart .ct-series.ct-series-k .ct-line,.ct-chart .ct-series.ct-series-k .ct-point,.ct-chart .ct-series.ct-series-k .ct-slice.ct-donut{stroke:#eacf7d}.ct-chart .ct-series.ct-series-k .ct-area,.ct-chart .ct-series.ct-series-k .ct-slice:not(.ct-donut){fill:#eacf7d}.ct-chart .ct-series.ct-series-l .ct-bar,.ct-chart .ct-series.ct-series-l .ct-line,.ct-chart .ct-series.ct-series-l .ct-point,.ct-chart .ct-series.ct-series-l .ct-slice.ct-donut{stroke:#86797d}.ct-chart .ct-series.ct-series-l .ct-area,.ct-chart .ct-series.ct-series-l .ct-slice:not(.ct-donut){fill:#86797d}.ct-chart .ct-series.ct-series-m .ct-bar,.ct-chart .ct-series.ct-series-m .ct-line,.ct-chart .ct-series.ct-series-m .ct-point,.ct-chart .ct-series.ct-series-m .ct-slice.ct-donut{stroke:#b2c326}.ct-chart .ct-series.ct-series-m .ct-area,.ct-chart .ct-series.ct-series-m .ct-slice:not(.ct-donut){fill:#b2c326}.ct-chart .ct-series.ct-series-n .ct-bar,.ct-chart .ct-series.ct-series-n .ct-line,.ct-chart .ct-series.ct-series-n .ct-point,.ct-chart .ct-series.ct-series-n .ct-slice.ct-donut{stroke:#6188e2}.ct-chart .ct-series.ct-series-n .ct-area,.ct-chart .ct-series.ct-series-n .ct-slice:not(.ct-donut){fill:#6188e2}.ct-chart .ct-series.ct-series-o .ct-bar,.ct-chart .ct-series.ct-series-o .ct-line,.ct-chart .ct-series.ct-series-o .ct-point,.ct-chart .ct-series.ct-series-o .ct-slice.ct-donut{stroke:#a748ca}.ct-chart .ct-series.ct-series-o .ct-area,.ct-chart .ct-series.ct-series-o .ct-slice:not(.ct-donut){fill:#a748ca}.ct-chart.ct-square{display:block;position:relative;width:100%}.ct-chart.ct-square:before{display:block;float:left;width:0;height:0;padding-bottom:100%}.ct-chart.ct-square:after{display:table}.ct-chart.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-second{display:block;position:relative;width:100%}.ct-chart.ct-minor-second:before{display:block;float:left;width:0;height:0;padding-bottom:93.75%}.ct-chart.ct-minor-second:after{display:table}.ct-chart.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-second{display:block;position:relative;width:100%}.ct-chart.ct-major-second:before{display:block;float:left;width:0;height:0;padding-bottom:88.8888888889%}.ct-chart.ct-major-second:after{display:table}.ct-chart.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-third{display:block;position:relative;width:100%}.ct-chart.ct-minor-third:before{display:block;float:left;width:0;height:0;padding-bottom:83.3333333333%}.ct-chart.ct-minor-third:after{display:table}.ct-chart.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-third{display:block;position:relative;width:100%}.ct-chart.ct-major-third:before{display:block;float:left;width:0;height:0;padding-bottom:80%}.ct-chart.ct-major-third:after{display:table}.ct-chart.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fourth:before{display:block;float:left;width:0;height:0;padding-bottom:75%}.ct-chart.ct-perfect-fourth:after{display:table}.ct-chart.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-chart.ct-perfect-fifth:before{display:block;float:left;width:0;height:0;padding-bottom:66.6666666667%}.ct-chart.ct-perfect-fifth:after{display:table}.ct-chart.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-sixth{display:block;position:relative;width:100%}.ct-chart.ct-minor-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:62.5%}.ct-chart.ct-minor-sixth:after{display:table}.ct-chart.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-golden-section{display:block;position:relative;width:100%}.ct-chart.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-chart.ct-golden-section:after{display:table;clear:both}.ct-chart.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-sixth{display:block;position:relative;width:100%}.ct-chart.ct-major-sixth:before{display:block;float:left;width:0;height:0;padding-bottom:60%}.ct-chart.ct-major-sixth:after{display:table}.ct-chart.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-minor-seventh{display:block;position:relative;width:100%}.ct-chart.ct-minor-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:56.25%}.ct-chart.ct-minor-seventh:after{display:table}.ct-chart.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-seventh{display:block;position:relative;width:100%}.ct-chart.ct-major-seventh:before{display:block;float:left;width:0;height:0;padding-bottom:53.3333333333%}.ct-chart.ct-major-seventh:after{display:table}.ct-chart.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-octave{display:block;position:relative;width:100%}.ct-chart.ct-octave:before{display:block;float:left;width:0;height:0;padding-bottom:50%}.ct-chart.ct-octave:after{display:table}.ct-chart.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-tenth{display:block;position:relative;width:100%}.ct-chart.ct-major-tenth:before{display:block;float:left;width:0;height:0;padding-bottom:40%}.ct-chart.ct-major-tenth:after{display:table}.ct-chart.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-eleventh{display:block;position:relative;width:100%}.ct-chart.ct-major-eleventh:before{display:block;float:left;width:0;height:0;padding-bottom:37.5%}.ct-chart.ct-major-eleventh:after{display:table}.ct-chart.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-major-twelfth{display:block;position:relative;width:100%}.ct-chart.ct-major-twelfth:before{display:block;float:left;width:0;height:0;padding-bottom:33.3333333333%}.ct-chart.ct-major-twelfth:after{display:table}.ct-chart.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-chart.ct-double-octave{display:block;position:relative;width:100%}.ct-chart.ct-double-octave:before{display:block;float:left;width:0;height:0;padding-bottom:25%}.ct-chart.ct-double-octave:after{display:table}.ct-chart.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-double-octave:after,.ct-double-octave:before,.ct-golden-section:after,.ct-major-eleventh:after,.ct-major-eleventh:before,.ct-major-second:after,.ct-major-second:before,.ct-major-seventh:after,.ct-major-seventh:before,.ct-major-sixth:after,.ct-major-sixth:before,.ct-major-tenth:after,.ct-major-tenth:before,.ct-major-third:after,.ct-major-third:before,.ct-major-twelfth:after,.ct-major-twelfth:before,.ct-minor-second:after,.ct-minor-second:before,.ct-minor-seventh:after,.ct-minor-seventh:before,.ct-minor-sixth:after,.ct-minor-sixth:before,.ct-minor-third:after,.ct-minor-third:before,.ct-octave:after,.ct-octave:before,.ct-perfect-fifth:after,.ct-perfect-fifth:before,.ct-perfect-fourth:after,.ct-perfect-fourth:before,.ct-square:after,.ct-square:before{content:""}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.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-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{fill:none;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;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;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;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;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;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;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;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;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{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;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;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;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;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;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;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;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;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/dist/chartist.min.js b/dist/chartist.min.js index 22ddf09e..18e9e428 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.8.2 +/* Chartist.js 0.8.3 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.8.2"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=void 0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a,b){function c(a){if(a instanceof Array)for(var b=0;bd.high&&(d.high=a),f&&ak,m=f?c.rho(j.range):0;if(f&&c.projectLength(a,1,j)>=d)j.step=1;else if(f&&m=d)j.step=m;else for(;;)if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,f&&j.step%1!==0){j.step*=2;break}}for(h=j.min,i=j.max;h+j.step<=j.low;)h+=j.step;for(;i-j.step>=j.high;)i-=j.step;for(j.min=h,j.max=i,j.range=j.max-j.min,j.values=[],g=j.min;g<=j.max;g+=j.step)j.values.push(c.roundWithPrecision(g));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f-10,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){var m={x:0,y:0};(l[k]||0===l[k])&&("x"===a.units.pos?(b.pos=d.x1+b.pos,m.x=h.axisX.labelOffset.x,"start"===h.axisX.position?m.y=d.padding.top+h.axisX.labelOffset.y+(g?5:20):m.y=d.y1+h.axisX.labelOffset.y+(g?5:20)):(b.pos=d.y1-b.pos,m.y=h.axisY.labelOffset.y-(g?b.len:0),"start"===h.axisY.position?m.x=g?d.padding.left+h.axisY.labelOffset.x:d.x1-10:m.x=d.x2+h.axisY.labelOffset.x+10),j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,m,f,[h.classNames.label,h.classNames[a.units.dir],h.classNames[j.position]],g,i))})},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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;ga.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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.classNames.slice+(a.donut?" "+a.classNames.donut:""));if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label", -index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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:{chart:"ct-chart-pie",series:"ct-series",slice:"ct-slice",donut:"ct-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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.8.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=void 0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a,b){function c(a){if(a instanceof Array)for(var b=0;bd.high&&(d.high=a),f&&ak,m=f?c.rho(j.range):0;if(f&&c.projectLength(a,1,j)>=d)j.step=1;else if(f&&m=d)j.step=m;else for(;;)if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,f&&j.step%1!==0){j.step*=2;break}}for(h=j.min,i=j.max;h+j.step<=j.low;)h+=j.step;for(;i-j.step>=j.high;)i-=j.step;for(j.min=h,j.max=i,j.range=j.max-j.min,j.values=[],g=j.min;g<=j.max;g+=j.step)j.values.push(c.roundWithPrecision(g));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f-10,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){var m={x:0,y:0};(l[k]||0===l[k])&&("x"===a.units.pos?(b.pos=d.x1+b.pos,m.x=h.axisX.labelOffset.x,"start"===h.axisX.position?m.y=d.padding.top+h.axisX.labelOffset.y+(g?5:20):m.y=d.y1+h.axisX.labelOffset.y+(g?5:20)):(b.pos=d.y1-b.pos,m.y=h.axisY.labelOffset.y-(g?b.len:0),"start"===h.axisY.position?m.x=g?d.padding.left+h.axisY.labelOffset.x:d.x1-10:m.x=d.x2+h.axisY.labelOffset.x+10),j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,m,f,[h.classNames.label,h.classNames[a.units.dir],h.classNames[j.position]],g,i))})},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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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,q).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,q)}).forEach(function(h){var i=b[g].elem("path",{d:h.stringify()},a.classNames.area,!0).attr({values:d[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:d[g],path:h.clone(),series:f,seriesIndex:g,chartRect:e,index:g,group:b[g],element:i})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:i.bounds,chartRect:e,axisX:h,axisY:i,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,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,showLine:!0,showPoint:!0,showArea:!1,areaBase:0,lineSmooth:!0,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",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=[],e=c.getDataArray(this.data,a.reverseData),g=a.distributeSeries?e.map(function(a){return[a]}):c.normalizeDataArray(e,this.data.labels.length);if(this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:"")),a.stackBars){var h=c.serialMap(g,function(){return Array.prototype.slice.call(arguments).reduce(c.sum,0)});b=c.getHighLow([h],a)}else b=c.getHighLow(g,a);b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var i,j,k,l,m,n=c.createChartRect(this.svg,a,f.padding);j=a.distributeSeries&&!a.stackBars?g.length:a.distributeSeries&&a.stackBars?1:this.data.labels.length,a.horizontalBars?(k=m=new c.StepAxis(c.Axis.units.y,n,{stepCount:j}),i=l=new c.LinearScaleAxis(c.Axis.units.x,n,{highLow:b,scaleMinSpace:a.axisX.scaleMinSpace,onlyInteger:a.axisX.onlyInteger,referenceValue:0})):(k=l=new c.StepAxis(c.Axis.units.x,n,{stepCount:j}),i=m=new c.LinearScaleAxis(c.Axis.units.y,n,{highLow:b,scaleMinSpace:a.axisY.scaleMinSpace,onlyInteger:a.axisY.onlyInteger,referenceValue:0}));var o=this.svg.elem("g").addClass(a.classNames.labelGroup),p=this.svg.elem("g").addClass(a.classNames.gridGroup),q=a.horizontalBars?n.x1+i.projectValue(0).pos:n.y1-i.projectValue(0).pos,r=[];c.createAxis(k,this.data.labels,n,p,o,this.supportsForeignObject,a,this.eventEmitter),c.createAxis(i,i.bounds.values,n,p,o,this.supportsForeignObject,a,this.eventEmitter),this.data.series.forEach(function(b,e){var f,h=e-(this.data.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?k.axisLength/g.length/2:a.distributeSeries&&a.stackBars?k.axisLength/2:k.axisLength/g[e].length/2,d[e]=this.svg.elem("g"),d[e].attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),d[e].addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),g[e].forEach(function(j,l){var m,o,p,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:l,m=a.horizontalBars?{x:n.x1+i.projectValue(j||0,l,g[e]).pos,y:n.y1-k.projectValue(j||0,s,g[e]).pos}:{x:n.x1+k.projectValue(j||0,s,g[e]).pos,y:n.y1-i.projectValue(j||0,l,g[e]).pos},m[k.units.pos]+=f*(a.horizontalBars?-1:1),m[k.units.pos]+=a.stackBars||a.distributeSeries?0:h*a.seriesBarDistance*(a.horizontalBars?-1:1),p=r[l]||q,r[l]=p-(q-m[k.counterUnits.pos]),void 0!==j){var t={};t[k.units.pos+"1"]=m[k.units.pos],t[k.units.pos+"2"]=m[k.units.pos],t[k.counterUnits.pos+"1"]=a.stackBars?p:q,t[k.counterUnits.pos+"2"]=a.stackBars?r[l]:m[k.counterUnits.pos],o=d[e].elem("line",t,a.classNames.bar).attr({value:j,meta:c.getMetaData(b,l)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:j,index:l,meta:c.getMetaData(b,l),series:b,seriesIndex:e,chartRect:n,group:d[e],element:o},t))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:i.bounds,chartRect:n,axisX:l,axisY:m,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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({ +style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index e6576344..6d249bd1 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","recursiveConvert","isNaN","hasOwnProperty","reversed","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","j","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","recursiveHighLow","findHigh","highLow","high","findLow","low","Number","MAX_VALUE","rho","num","gcd","p","q","f","x","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","y","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","removeEventListener","resizeListener","on","off","initialize","addEventListener","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","clearTimeout","setTimeout","Error","attributes","parent","insertFirst","Element","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","joinedPath","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","smoothing","point","areaBase","areaBaseProjected","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisStepCount","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","total","previousValue","currentValue","donut","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.8.2\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.8.2'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n // Rcursively 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(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) {\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n return +value;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = undefined;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray, options) {\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 findHigh = options.high === undefined,\n 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 instanceof Array) {\n for (var i = 0; i < data.length; i++) {\n recursiveHighLow(data[i]);\n }\n } else {\n if (findHigh && data > highLow.high) {\n highLow.high = data;\n }\n\n if (findLow && data < highLow.low) {\n highLow.low = data;\n }\n }\n }\n\n // Start to find highest and lowest number recursively\n recursiveHighLow(dataArray);\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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 }\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = 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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()];\n var projectedValues = data.map(axis.projectValue.bind(axis));\n var labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\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(axis.units.pos === 'x') {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n labelOffset.x = options.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(options.axisX.position === 'start') {\n labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 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(options.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10;\n } else {\n labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir],\n options.classNames[axisOptions.position]\n ], useForeignObject, eventEmitter);\n }\n });\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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 window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\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.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 if(this.container.__chartist__.initializeTimeoutId) {\n // If the initializeTimeoutId is still set we can safely assume that the initialization function has not\n // been called yet from the event loop. Therefore we should cancel the timeout and don't need to detach\n window.clearTimeout(this.container.__chartist__.initializeTimeoutId);\n } else {\n // The timeout reference has already been reset which means we need to detach the old chart first\n this.container.__chartist__.detach();\n }\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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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 * @return {Chartist.Svg.Path}\n */\n function clone() {\n var c = new Chartist.Svg.Path(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 * 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 });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n Chartist.Svg.Path.join = join;\n}(window, document, Chartist));\n;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, 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.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / this.bounds.range,\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 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 // 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 // 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 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 seriesGroups = [];\n var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var highLow = Chartist.getHighLow(normalizedData, options);\n\n var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n });\n\n var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger\n });\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\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 };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : 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 = seriesGroups[seriesIndex].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 'value': pathElement.data.value,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 group: seriesGroups[seriesIndex],\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(seriesOptions.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\n\n // Clone original path and splice our new area path to add the missing path elements to close the area shape\n var areaPath = path.clone();\n // Modify line path and add missing elements for area\n areaPath.position(0)\n .remove(1)\n .move(chartRect.x1, areaBaseProjected)\n .line(pathCoordinates[0], pathCoordinates[1])\n .position(areaPath.pathElements.length)\n .line(pathCoordinates[pathCoordinates.length - 2], areaBaseProjected);\n\n // Create the new path for the area shape with the area class from the options\n var area = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: area\n });\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 seriesGroups = [];\n var data = Chartist.getDataArray(this.data, options.reverseData);\n var normalizedData = options.distributeSeries ? data.map(function(value) {\n return [value];\n }) : Chartist.normalizeDataArray(data, this.data.labels.length);\n var highLow;\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 if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(normalizedData, options);\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 labelAxisStepCount,\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 but stacked bars aren't, we need to use the one dimensional series array\n // length as step count for the label axis\n labelAxisStepCount = normalizedData.length;\n } else 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 set step\n // count to 1\n labelAxisStepCount = 1;\n } else {\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length\n // as the bars are normalized\n labelAxisStepCount = this.data.labels.length;\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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n onlyInteger: options.axisX.onlyInteger,\n referenceValue: 0\n });\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger,\n referenceValue: 0\n });\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength;\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 / normalizedData.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 / normalizedData[seriesIndex].length / 2;\n }\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[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 || 0, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 chart: 'ct-chart-pie',\n series: 'ct-series',\n slice: 'ct-slice',\n donut: 'ct-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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].elem('path', {\n d: path.stringify()\n }, options.classNames.slice + (options.donut ? ' ' + options.classNames.donut : ''));\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","recursiveConvert","isNaN","hasOwnProperty","reversed","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","j","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","recursiveHighLow","findHigh","highLow","high","findLow","low","Number","MAX_VALUE","rho","gcd","p","q","f","x","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","y","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","setTimeout","Error","attributes","parent","insertFirst","Element","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","splitByCommand","joinedPath","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","smoothing","point","areaBase","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisStepCount","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.8.3\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.8.3'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n // Rcursively 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(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) {\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n return +value;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = undefined;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray, options) {\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 findHigh = options.high === undefined,\n 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 instanceof Array) {\n for (var i = 0; i < data.length; i++) {\n recursiveHighLow(data[i]);\n }\n } else {\n if (findHigh && data > highLow.high) {\n highLow.high = data;\n }\n\n if (findLow && data < highLow.low) {\n highLow.low = data;\n }\n }\n }\n\n // Start to find highest and lowest number recursively\n recursiveHighLow(dataArray);\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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 }\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = 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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()];\n var projectedValues = data.map(axis.projectValue.bind(axis));\n var labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\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(axis.units.pos === 'x') {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n labelOffset.x = options.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(options.axisX.position === 'start') {\n labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 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(options.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10;\n } else {\n labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir],\n options.classNames[axisOptions.position]\n ], useForeignObject, eventEmitter);\n }\n });\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, 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.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / this.bounds.range,\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 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 // 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 // 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 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 seriesGroups = [];\n var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var highLow = Chartist.getHighLow(normalizedData, options);\n\n var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n });\n\n var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger\n });\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\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 };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : 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 = seriesGroups[seriesIndex].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 'value': pathElement.data.value,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 group: seriesGroups[seriesIndex],\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(seriesOptions.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\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 = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 seriesGroups = [];\n var data = Chartist.getDataArray(this.data, options.reverseData);\n var normalizedData = options.distributeSeries ? data.map(function(value) {\n return [value];\n }) : Chartist.normalizeDataArray(data, this.data.labels.length);\n var highLow;\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 if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(normalizedData, options);\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 labelAxisStepCount,\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 but stacked bars aren't, we need to use the one dimensional series array\n // length as step count for the label axis\n labelAxisStepCount = normalizedData.length;\n } else 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 set step\n // count to 1\n labelAxisStepCount = 1;\n } else {\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length\n // as the bars are normalized\n labelAxisStepCount = this.data.labels.length;\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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n onlyInteger: options.axisX.onlyInteger,\n referenceValue: 0\n });\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger,\n referenceValue: 0\n });\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength;\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 / normalizedData.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 / normalizedData[seriesIndex].length / 2;\n }\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[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 || 0, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/dist/scss/chartist.scss b/dist/scss/chartist.scss index fe68f886..0f19ba05 100644 --- a/dist/scss/chartist.scss +++ b/dist/scss/chartist.scss @@ -62,7 +62,6 @@ color: $ct-text-color; font-size: $ct-text-size; line-height: $ct-text-line-height; - alignment-baseline: middle; } @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { @@ -104,11 +103,11 @@ } @mixin ct-chart-series-color($color) { - .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice}.#{$ct-class-donut} { + .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice-donut} { stroke: $color; } - .#{$ct-class-slice}:not(.#{$ct-class-donut}), .#{$ct-class-area} { + .#{$ct-class-slice-pie}, .#{$ct-class-area} { fill: $color; } } @@ -205,32 +204,28 @@ @include ct-chart-bar($ct-bar-width); } - .#{$ct-class-slice}.#{$ct-class-donut} { + .#{$ct-class-slice-donut} { @include ct-chart-donut($ct-donut-width); } @if $ct-include-colored-series { - .#{$ct-class-series} { - @for $i from 0 to length($ct-series-names) { - &.#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { - $color: nth($ct-series-colors, $i + 1); + @for $i from 0 to length($ct-series-names) { + .#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { + $color: nth($ct-series-colors, $i + 1); - @include ct-chart-series-color($color); - } + @include ct-chart-series-color($color); } } } } @if $ct-include-classes { - .#{$ct-class-chart} { - @include ct-chart(); - - @if $ct-include-alternative-responsive-containers { - @for $i from 0 to length($ct-scales-names) { - &.#{nth($ct-scales-names, $i + 1)} { - @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); - } + @include ct-chart(); + + @if $ct-include-alternative-responsive-containers { + @for $i from 0 to length($ct-scales-names) { + .#{nth($ct-scales-names, $i + 1)} { + @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); } } } diff --git a/dist/scss/settings/_chartist-settings.scss b/dist/scss/settings/_chartist-settings.scss index af242f49..21b92c13 100644 --- a/dist/scss/settings/_chartist-settings.scss +++ b/dist/scss/settings/_chartist-settings.scss @@ -8,14 +8,15 @@ $ct-class-chart-line: ct-chart-line !default; $ct-class-chart-bar: ct-chart-bar !default; $ct-class-horizontal-bars: ct-horizontal-bars !default; $ct-class-chart-pie: ct-chart-pie !default; +$ct-class-chart-donut: ct-chart-donut !default; $ct-class-label: ct-label !default; $ct-class-series: ct-series !default; $ct-class-line: ct-line !default; $ct-class-point: ct-point !default; $ct-class-area: ct-area !default; $ct-class-bar: ct-bar !default; -$ct-class-slice: ct-slice !default; -$ct-class-donut: ct-donut !default; +$ct-class-slice-pie: ct-slice-pie !default; +$ct-class-slice-donut: ct-slice-donut !default; $ct-class-grid: ct-grid !default; $ct-class-vertical: ct-vertical !default; $ct-class-horizontal: ct-horizontal !default; diff --git a/package.json b/package.json index ff05ede8..0a327544 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.8.2", + "version": "0.8.3", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From be9e6b6b10a1cb042f63ecac8e64acb7b3a0d077 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 9 Jun 2015 00:07:23 +0200 Subject: [PATCH 270/593] Major refactoring of axis and projection code, added possibility to configure axes when creating a chart --- site/layouts/default.hbs | 1 + site/styles/main.scss | 10 +- src/scripts/axes/axis.js | 76 +++++++++++++- src/scripts/axes/continuous-axis.js | 50 ++++++++++ src/scripts/axes/linear-scale-axis.js | 14 +-- src/scripts/axes/step-axis.js | 10 +- src/scripts/charts/bar.js | 127 ++++++++++-------------- src/scripts/charts/line.js | 106 ++++++++++---------- src/scripts/core.js | 138 +++++++++----------------- tasks/concat.js | 1 + 10 files changed, 295 insertions(+), 238 deletions(-) create mode 100644 src/scripts/axes/continuous-axis.js diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index af47a09f..3846dc06 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -63,6 +63,7 @@ + diff --git a/site/styles/main.scss b/site/styles/main.scss index 20fdcc0b..8d26eba6 100644 --- a/site/styles/main.scss +++ b/site/styles/main.scss @@ -130,13 +130,11 @@ code { margin-bottom: 1rem; } -.ct-chart-pie { - .ct-label { - font-size: 1em; +.ct-chart-pie .ct-label, .ct-chart-donut .ct-label { + font-size: 1em; - @media #{$small-only} { - fill: rgba(255, 255, 255, 0.8); - } + @media #{$small-only} { + fill: rgba(255, 255, 255, 0.8); } } diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 4a586891..9e498343 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -26,17 +26,91 @@ } }; - function Axis(units, chartRect, options) { + function Axis(units, chartRect, ticks, options) { this.units = units; this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; this.chartRect = chartRect; this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; this.gridOffset = chartRect[units.rectOffset]; + this.ticks = ticks; this.options = options; } + function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) { + var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; + var projectedValues = this.ticks.map(this.projectValue.bind(this)); + var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); + + projectedValues.forEach(function(projectedValue, index) { + var labelOffset = { + x: 0, + y: 0 + }; + + // TODO: Find better solution for solving this problem + // Calculate how much space we have available for the label + var labelLength; + if(projectedValues[index + 1]) { + // If we still have one label ahead, we can calculate the distance to the next tick / label + labelLength = projectedValues[index + 1] - projectedValue; + } else { + // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to + // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will + // still be visible inside of the chart padding. + labelLength = Math.max(this.axisLength - projectedValue, 30); + } + + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + if(!labelValues[index] && labelValues[index] !== 0) { + return; + } + + // Transform to global coordinates using the chartRect + // We also need to set the label offset for the createLabel function + if(this.units.pos === 'x') { + projectedValue = this.chartRect.x1 + projectedValue; + labelOffset.x = chartOptions.axisX.labelOffset.x; + + // If the labels should be positioned in start position (top side for vertical axis) we need to set a + // different offset as for positioned with end (bottom) + if(chartOptions.axisX.position === 'start') { + labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } else { + labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } + } else { + projectedValue = this.chartRect.y1 - projectedValue; + labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0); + + // If the labels should be positioned in start position (left side for horizontal axis) we need to set a + // different offset as for positioned with end (right side) + if(chartOptions.axisY.position === 'start') { + labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10; + } else { + labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; + } + } + + if(axisOptions.showGrid) { + Chartist.createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [ + chartOptions.classNames.grid, + chartOptions.classNames[this.units.dir] + ], eventEmitter); + } + + if(axisOptions.showLabel) { + Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [ + chartOptions.classNames.label, + chartOptions.classNames[this.units.dir], + chartOptions.classNames[axisOptions.position] + ], useForeignObject, eventEmitter); + } + }.bind(this)); + } + Chartist.Axis = Chartist.Class.extend({ constructor: Axis, + createGridAndLabels: createGridAndLabels, projectValue: function(value, index, data) { throw new Error('Base axis can\'t be instantiated!'); } diff --git a/src/scripts/axes/continuous-axis.js b/src/scripts/axes/continuous-axis.js new file mode 100644 index 00000000..c4ede83d --- /dev/null +++ b/src/scripts/axes/continuous-axis.js @@ -0,0 +1,50 @@ +/** + * The continuous axis uses standard linear continuous 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. + * + * *options* + * 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. + * ``` + * var options = { + * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored + * high: 100, + * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored + * low: 0, + * // 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. + * divisor: 4, + * // 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. + * ticks: [1, 10, 20, 30] + * }; + * ``` + * + * @module Chartist.ContinuousAxis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + function ContinuousAxis(axisUnit, data, chartRect, options) { + this.highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); + this.divisor = options.divisor || 1; + this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { + return this.highLow.low + (this.highLow.high - this.highLow.low) / this.divisor * index; + }.bind(this)); + + Chartist.ContinuousAxis.super.constructor.call(this, + axisUnit, + chartRect, + this.ticks, + options); + + this.stepLength = this.axisLength / this.divisor; + } + + function projectValue(value) { + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.highLow.low) / (this.highLow.high - this.highLow.low); + } + + Chartist.ContinuousAxis = Chartist.Axis.extend({ + constructor: ContinuousAxis, + projectValue: projectValue + }); + +}(window, document, Chartist)); diff --git a/src/scripts/axes/linear-scale-axis.js b/src/scripts/axes/linear-scale-axis.js index d58c3137..554cebeb 100644 --- a/src/scripts/axes/linear-scale-axis.js +++ b/src/scripts/axes/linear-scale-axis.js @@ -7,20 +7,20 @@ (function (window, document, Chartist) { 'use strict'; - function LinearScaleAxis(axisUnit, chartRect, options) { + function LinearScaleAxis(axisUnit, data, chartRect, options) { + // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options + this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger); + Chartist.LinearScaleAxis.super.constructor.call(this, axisUnit, chartRect, + this.bounds.values, options); - - this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger); } function projectValue(value) { - return { - pos: this.axisLength * (value - this.bounds.min) / this.bounds.range, - len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) - }; + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; } Chartist.LinearScaleAxis = Chartist.Axis.extend({ diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index 10c224bb..369b8d35 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -7,20 +7,18 @@ (function (window, document, Chartist) { 'use strict'; - function StepAxis(axisUnit, chartRect, options) { + function StepAxis(axisUnit, data, chartRect, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, chartRect, + options.ticks, options); - this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); + this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0)); } function projectValue(value, index) { - return { - pos: this.stepLength * index, - len: this.stepLength - }; + return this.stepLength * index; } Chartist.StepAxis = Chartist.Axis.extend({ diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index d7d0e0fa..16958adb 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -106,11 +106,13 @@ * */ function createChart(options) { - var seriesGroups = []; - var data = Chartist.getDataArray(this.data, options.reverseData); - var normalizedData = options.distributeSeries ? data.map(function(value) { - return [value]; - }) : Chartist.normalizeDataArray(data, this.data.labels.length); + var data = { + raw: this.data, + normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) { + return [value]; + }) : Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length) + }; + var highLow; // Create new svg element @@ -121,15 +123,20 @@ options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '') ); + // Drawing groups in correct order + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + if(options.stackBars) { // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = Chartist.serialMap(normalizedData, function serialSums() { + var serialSums = Chartist.serialMap(data.normalized, function serialSums() { return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); }); highLow = Chartist.getHighLow([serialSums], options); } else { - highLow = Chartist.getHighLow(normalizedData, options); + highLow = Chartist.getHighLow(data.normalized, options); } // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); @@ -138,117 +145,91 @@ var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, - labelAxisStepCount, + labelAxisTicks, labelAxis, axisX, axisY; // We need to set step count based on some options combinations - if(options.distributeSeries && !options.stackBars) { - // If distributed series are enabled but stacked bars aren't, we need to use the one dimensional series array - // length as step count for the label axis - labelAxisStepCount = normalizedData.length; - } else if(options.distributeSeries && options.stackBars) { - // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore set step - // count to 1 - labelAxisStepCount = 1; + if(options.distributeSeries && options.stackBars) { + // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should + // use only the first label for the step axis + labelAxisTicks = data.raw.labels.slice(0, 1); } else { - // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length + // If distributed series are enabled but stacked bars aren't, we should use the series labels + // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array // as the bars are normalized - labelAxisStepCount = this.data.labels.length; + labelAxisTicks = data.raw.labels; } // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { - labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, { - stepCount: labelAxisStepCount + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { + ticks: labelAxisTicks }); - valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, { + valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, - scaleMinSpace: options.axisX.scaleMinSpace, - onlyInteger: options.axisX.onlyInteger, referenceValue: 0 - }); + })); } else { - labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { - stepCount: labelAxisStepCount + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { + ticks: labelAxisTicks }); - valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { + valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - onlyInteger: options.axisY.onlyInteger, referenceValue: 0 - }); + })); } - // Start drawing - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), - gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup), - // Projected 0 point - zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos), - // Used to track the screen coordinates of stacked bars - stackedBarValues = []; + // Projected 0 point + var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0)); + // Used to track the screen coordinates of stacked bars + var stackedBarValues = []; - Chartist.createAxis( - labelAxis, - this.data.labels, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); - - Chartist.createAxis( - valueAxis, - valueAxis.bounds.values, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); + labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); // Draw the series - this.data.series.forEach(function(series, seriesIndex) { + data.raw.series.forEach(function(series, seriesIndex) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = seriesIndex - (this.data.series.length - 1) / 2, + var biPol = seriesIndex - (data.raw.series.length - 1) / 2; // Half of the period width between vertical grid lines used to position bars - periodHalfLength; + var periodHalfLength; + // Current series SVG element + var seriesElement; // We need to set periodHalfLength based on some options combinations if(options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array // which is the series count and divide by 2 - periodHalfLength = labelAxis.axisLength / normalizedData.length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized.length / 2; } else if(options.distributeSeries && options.stackBars) { // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis // length by 2 periodHalfLength = labelAxis.axisLength / 2; } else { // On regular bar charts we should just use the series length - periodHalfLength = labelAxis.axisLength / normalizedData[seriesIndex].length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized[seriesIndex].length / 2; } - seriesGroups[seriesIndex] = this.svg.elem('g'); + // Adding the series group to the series element + seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[seriesIndex].attr({ + seriesElement.attr({ 'series-name': series.name, 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[seriesIndex].addClass([ + seriesElement.addClass([ options.classNames.series, (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - normalizedData[seriesIndex].forEach(function(value, valueIndex) { + data.normalized[seriesIndex].forEach(function(value, valueIndex) { var projected, bar, previousStack, @@ -271,13 +252,13 @@ // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]) } } @@ -302,7 +283,7 @@ positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; - bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({ + bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'value': value, 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); @@ -315,7 +296,7 @@ series: series, seriesIndex: seriesIndex, chartRect: chartRect, - group: seriesGroups[seriesIndex], + group: seriesElement, element: bar }, positions)); }.bind(this)); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 21279864..1e2fd275 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -32,6 +32,10 @@ showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, + // Set the axis type to be used to project values on this axis + type: Chartist.Axis.StepAxis, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20, // Use only integer values (whole numbers) for the scale steps onlyInteger: false }, @@ -52,6 +56,8 @@ showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, + // Set the axis type to be used to project values on this axis + type: Chartist.Axis.LinearScaleAxis, // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20, // Use only integer values (whole numbers) for the scale steps @@ -109,64 +115,54 @@ * */ function createChart(options) { - var seriesGroups = []; - var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); + var data = { + raw: this.data, + normalized: Chartist.getDataArray(this.data, options.reverseData, true) + }; // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + // Create groups for labels, grid and series + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); - var highLow = Chartist.getHighLow(normalizedData, options); - - var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { - stepCount: this.data.labels.length, - stretch: options.fullWidth - }); + var axisX, axisY; - var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - onlyInteger: options.axisY.onlyInteger - }); - - // Start drawing - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), - gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + if(options.axisX.type === undefined) { + axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + ticks: data.raw.labels, + stretch: options.fullWidth + })); + } else { + axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + } - Chartist.createAxis( - axisX, - this.data.labels, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); + if(options.axisY.type === undefined) { + axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + high: Chartist.isNum(options.high) ? options.high : options.axisY.high, + low: Chartist.isNum(options.low) ? options.low : options.axisY.low + })); + } else { + axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + } - Chartist.createAxis( - axisY, - axisY.bounds.values, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); + axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); // Draw the series - this.data.series.forEach(function(series, seriesIndex) { - seriesGroups[seriesIndex] = this.svg.elem('g'); + data.raw.series.forEach(function(series, seriesIndex) { + var seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[seriesIndex].attr({ + seriesElement.attr({ 'series-name': series.name, 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[seriesIndex].addClass([ + seriesElement.addClass([ options.classNames.series, (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); @@ -174,10 +170,10 @@ var pathCoordinates = [], pathData = []; - normalizedData[seriesIndex].forEach(function(value, valueIndex) { + data.normalized[seriesIndex].forEach(function(value, valueIndex) { var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[seriesIndex]) }; pathCoordinates.push(p.x, p.y); pathData.push({ @@ -206,7 +202,7 @@ if (seriesOptions.showPoint) { path.pathElements.forEach(function(pathElement) { - var point = seriesGroups[seriesIndex].elem('line', { + var point = seriesElement.elem('line', { x1: pathElement.x, y1: pathElement.y, x2: pathElement.x + 0.01, @@ -223,7 +219,7 @@ meta: pathElement.data.meta, series: series, seriesIndex: seriesIndex, - group: seriesGroups[seriesIndex], + group: seriesElement, element: point, x: pathElement.x, y: pathElement.y @@ -232,21 +228,21 @@ } if(seriesOptions.showLine) { - var line = seriesGroups[seriesIndex].elem('path', { + var line = seriesElement.elem('path', { d: path.stringify() }, options.classNames.line, true).attr({ - 'values': normalizedData[seriesIndex] + 'values': data.normalized[seriesIndex] }, Chartist.xmlNs.uri); this.eventEmitter.emit('draw', { type: 'line', - values: normalizedData[seriesIndex], + values: data.normalized[seriesIndex], path: path.clone(), chartRect: chartRect, index: seriesIndex, series: series, seriesIndex: seriesIndex, - group: seriesGroups[seriesIndex], + group: seriesElement, element: line }); } @@ -257,7 +253,7 @@ var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); // We project the areaBase value into screen coordinates - var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); // In order to form the area we'll first split the path by move commands so we can chunk it up into segments path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { @@ -283,22 +279,22 @@ }).forEach(function createArea(areaPath) { // For each of our newly created area paths, we'll now create path elements by stringifying our path objects // and adding the created DOM elements to the correct series group - var area = seriesGroups[seriesIndex].elem('path', { + var area = seriesElement.elem('path', { d: areaPath.stringify() }, options.classNames.area, true).attr({ - 'values': normalizedData[seriesIndex] + 'values': data.normalized[seriesIndex] }, Chartist.xmlNs.uri); // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { type: 'area', - values: normalizedData[seriesIndex], + values: data.normalized[seriesIndex], path: areaPath.clone(), series: series, seriesIndex: seriesIndex, chartRect: chartRect, index: seriesIndex, - group: seriesGroups[seriesIndex], + group: seriesElement, element: area }); }.bind(this)); diff --git a/src/scripts/core.js b/src/scripts/core.js index 7dc5ba62..c452bafe 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -333,7 +333,7 @@ var Chartist = { * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ - Chartist.getDataArray = function (data, reverse) { + Chartist.getDataArray = function (data, reverse, multi) { // If the data should be reversed but isn't we need to reverse it // If it's reversed but it shouldn't we need to reverse it back // That's required to handle data updates correctly and to reflect the responsive configurations @@ -352,7 +352,14 @@ var Chartist = { } else if(value.hasOwnProperty('value')) { return recursiveConvert(value.value); } else { - return +value; + if(multi) { + return { + x: value.hasOwnProperty('x') ? value.x : undefined, + y: value.hasOwnProperty('y') ? value.y : +value + }; + } else { + return +value; + } } } @@ -450,11 +457,15 @@ var Chartist = { * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. * * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart + * @param {Array} data The array that contains the data to be visualized in the chart * @param {Object} options The Object that contains all the optional values for the chart + * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ - Chartist.getHighLow = function (dataArray, options) { + Chartist.getHighLow = function (data, options, dimension) { + // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred + options = Chartist.extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {}); + var highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low @@ -464,23 +475,27 @@ var Chartist = { // Function to recursively walk through arrays and find highest and lowest number function recursiveHighLow(data) { - if(data instanceof Array) { + if(data === undefined) { + return undefined; + } else if(data instanceof Array) { for (var i = 0; i < data.length; i++) { recursiveHighLow(data[i]); } } else { - if (findHigh && data > highLow.high) { - highLow.high = data; + var value = dimension ? +data[dimension] : +data; + + if (findHigh && value > highLow.high) { + highLow.high = value; } - if (findLow && data < highLow.low) { - highLow.low = data; + if (findLow && value < highLow.low) { + highLow.low = value; } } } // Start to find highest and lowest number recursively - recursiveHighLow(dataArray); + recursiveHighLow(data); // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity @@ -500,6 +515,20 @@ var Chartist = { return highLow; }; + Chartist.isNum = function(value) { + return !isNaN(value) && isFinite(value); + }; + + Chartist.getMultiValue = function(value, dimension) { + if(+value+'' === value+'') { + return +value; + } else if(value) { + return value[dimension]; + } else { + return undefined; + } + }; + /** * 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. * @@ -707,7 +736,7 @@ var Chartist = { * Creates a grid line based on a projected value. * * @memberof Chartist.Core - * @param projectedValue + * @param position * @param index * @param axis * @param offset @@ -716,10 +745,10 @@ var Chartist = { * @param classes * @param eventEmitter */ - Chartist.createGrid = function(projectedValue, index, axis, offset, length, group, classes, eventEmitter) { + Chartist.createGrid = function(position, index, axis, offset, length, group, classes, eventEmitter) { var positionalData = {}; - positionalData[axis.units.pos + '1'] = projectedValue.pos; - positionalData[axis.units.pos + '2'] = projectedValue.pos; + positionalData[axis.units.pos + '1'] = position; + positionalData[axis.units.pos + '2'] = position; positionalData[axis.counterUnits.pos + '1'] = offset; positionalData[axis.counterUnits.pos + '2'] = offset + length; @@ -741,7 +770,8 @@ var Chartist = { * Creates a label based on a projected value and an axis. * * @memberof Chartist.Core - * @param projectedValue + * @param position + * @param length * @param index * @param labels * @param axis @@ -752,13 +782,13 @@ var Chartist = { * @param useForeignObject * @param eventEmitter */ - Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + Chartist.createLabel = function(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { var labelElement; var positionalData = {}; - positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; + positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; - positionalData[axis.units.len] = projectedValue.len; + positionalData[axis.units.len] = length; positionalData[axis.counterUnits.len] = axisOffset - 10; if(useForeignObject) { @@ -786,78 +816,6 @@ var Chartist = { }, positionalData)); }; - /** - * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect. - * - * @memberof Chartist.Core - * @param axis - * @param data - * @param chartRect - * @param gridGroup - * @param labelGroup - * @param useForeignObject - * @param options - * @param eventEmitter - */ - Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { - var axisOptions = options['axis' + axis.units.pos.toUpperCase()]; - var projectedValues = data.map(axis.projectValue.bind(axis)); - var labelValues = data.map(axisOptions.labelInterpolationFnc); - - projectedValues.forEach(function(projectedValue, index) { - var labelOffset = { - x: 0, - y: 0 - }; - - // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!labelValues[index] && labelValues[index] !== 0) { - return; - } - - // Transform to global coordinates using the chartRect - // We also need to set the label offset for the createLabel function - if(axis.units.pos === 'x') { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - labelOffset.x = options.axisX.labelOffset.x; - - // If the labels should be positioned in start position (top side for vertical axis) we need to set a - // different offset as for positioned with end (bottom) - if(options.axisX.position === 'start') { - labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); - } else { - labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); - } - } else { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 0); - - // If the labels should be positioned in start position (left side for horizontal axis) we need to set a - // different offset as for positioned with end (right side) - if(options.axisY.position === 'start') { - labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10; - } else { - labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10; - } - } - - if(axisOptions.showGrid) { - Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ - options.classNames.grid, - options.classNames[axis.units.dir] - ], eventEmitter); - } - - if(axisOptions.showLabel) { - Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [ - options.classNames.label, - options.classNames[axis.units.dir], - options.classNames[axisOptions.position] - ], useForeignObject, eventEmitter); - } - }); - }; - /** * Helper to read series specific options from options object. It automatically falls back to the global option if * there is no option in the series options. diff --git a/tasks/concat.js b/tasks/concat.js index 582125d7..87f3755f 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -28,6 +28,7 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/scripts/axes/axis.js', '<%= pkg.config.src %>/scripts/axes/linear-scale-axis.js', '<%= pkg.config.src %>/scripts/axes/step-axis.js', + '<%= pkg.config.src %>/scripts/axes/continuous-axis.js', '<%= pkg.config.src %>/scripts/charts/line.js', '<%= pkg.config.src %>/scripts/charts/bar.js', '<%= pkg.config.src %>/scripts/charts/pie.js' From 9e1f2d5f6683aa85adba987787cf6f63416f1f76 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 9 Jun 2015 14:32:03 +0200 Subject: [PATCH 271/593] Fixed tests and stabilized multi dimensional value handling --- src/scripts/charts/bar.js | 2 +- src/scripts/core.js | 74 +++++++++++++++++++++------------- test/spec/spec-core.js | 77 +++++++++++++++++++++--------------- test/spec/spec-line-chart.js | 72 ++++++++++++++++----------------- 4 files changed, 129 insertions(+), 96 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 16958adb..35b26075 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -110,7 +110,7 @@ raw: this.data, normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) { return [value]; - }) : Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length) + }) : Chartist.getDataArray(this.data, options.reverseData) }; var highLow; diff --git a/src/scripts/core.js b/src/scripts/core.js index c452bafe..455162e6 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -331,6 +331,7 @@ var Chartist = { * @memberof Chartist.Core * @param {Object} data The series object that contains the data to be visualized in the chart * @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. + * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ Chartist.getDataArray = function (data, reverse, multi) { @@ -342,10 +343,11 @@ var Chartist = { data.reversed = !data.reversed; } - // Rcursively walks through nested arrays and convert string values to numbers and objects with value properties + // Recursively walks through nested arrays and convert string values to numbers and objects with value properties // to values. Check the tests in data core -> data normalization for a detailed specification of expected values function recursiveConvert(value) { - if(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) { + if(Chartist.isFalseyButZero(value)) { + // This is a hole in data and we should return undefined return undefined; } else if((value.data || value) instanceof Array) { return (value.data || value).map(recursiveConvert); @@ -354,11 +356,13 @@ var Chartist = { } else { if(multi) { return { - x: value.hasOwnProperty('x') ? value.x : undefined, - y: value.hasOwnProperty('y') ? value.y : +value + x: Chartist.getNumberOrUndefined(value.x), + // Single series value arrays are assumed to specify the Y-Axis value + // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] + y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value) }; } else { - return +value; + return Chartist.getNumberOrUndefined(value); } } } @@ -390,28 +394,6 @@ var Chartist = { }; }; - /** - * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. - * @param {Number} length The length of the x-axis data array. - * @return {Array} The array that got updated with missing values. - */ - Chartist.normalizeDataArray = function (dataArray, length) { - for (var i = 0; i < dataArray.length; i++) { - if (dataArray[i].length === length) { - continue; - } - - for (var j = dataArray[i].length; j < length; j++) { - dataArray[i][j] = undefined; - } - } - - return dataArray; - }; - Chartist.getMetaData = function(series, index) { var value = series.data ? series.data[index] : series[index]; return value ? Chartist.serialize(value.meta) : undefined; @@ -515,12 +497,48 @@ var Chartist = { return highLow; }; + /** + * Checks if the value is a valid number or string with a number. + * + * @memberof Chartist.Core + * @param value + * @returns {Boolean} + */ Chartist.isNum = function(value) { return !isNaN(value) && isFinite(value); }; + /** + * Returns true on all falsey values except the numeric value 0. + * + * @memberof Chartist.Core + * @param value + * @returns {boolean} + */ + Chartist.isFalseyButZero = function(value) { + return !value && value !== 0; + }; + + /** + * 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. + * + * @memberof Chartist.Core + * @param value + * @returns {*} + */ + Chartist.getNumberOrUndefined = function(value) { + return isNaN(+value) ? undefined : +value; + }; + + /** + * 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 undefined. + * + * @param value + * @param dimension + * @returns {*} + */ Chartist.getMultiValue = function(value, dimension) { - if(+value+'' === value+'') { + if(Chartist.isNum(value)) { return +value; } else if(value) { return value[dimension]; diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index f5170d72..f1710da0 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -84,24 +84,6 @@ describe('Chartist core', function() { }); describe('data normalization tests', function () { - it('should normalize based on label length', function() { - var data = { - labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - series: [ - [1, 2, 3, 4, 5, 6], - [1, 2, 3, 4, 5, 6, 7, 8], - [1, 2, 3] - ] - }; - - expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( - [ - [1, 2, 3, 4, 5, 6, undefined, undefined, undefined, undefined], - [1, 2, 3, 4, 5, 6, 7, 8, undefined, undefined], - [1, 2, 3, undefined, undefined, undefined, undefined, undefined, undefined, undefined] - ] - ); - }); it('normalize mixed series types correctly', function() { var data = { @@ -113,11 +95,11 @@ describe('Chartist core', function() { ] }; - expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( + expect(Chartist.getDataArray(data)).toEqual( [ - [1, 0, 3, 4, 5, 6, undefined, undefined, undefined, undefined], - [1, 0, 3, 4, 5, 6, 7, 8, undefined, undefined], - [1, 0, 3, undefined, undefined, undefined, undefined, undefined, undefined, undefined] + [1, 0, 3, 4, 5, 6], + [1, 0, 3, 4, 5, 6, 7, 8], + [1, 0, 3] ] ); }); @@ -152,11 +134,11 @@ describe('Chartist core', function() { ] }; - expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( + expect(Chartist.getDataArray(data)).toEqual( [ - [1, 0, 3, 4, 5, 6, undefined, undefined, undefined, undefined], - [1, 0, 3, 4, 5, 6, 7, 8, undefined, undefined], - [1, 0, 3, undefined, undefined, undefined, undefined, undefined, undefined, undefined] + [1, 0, 3, 4, 5, 6], + [1, 0, 3, 4, 5, 6, 7, 8], + [1, 0, 3] ] ); }); @@ -171,11 +153,11 @@ describe('Chartist core', function() { ] }; - expect(Chartist.normalizeDataArray(Chartist.getDataArray(data), data.labels.length)).toEqual( + expect(Chartist.getDataArray(data)).toEqual( [ - [undefined, undefined, undefined, 4, 5, 6, undefined, undefined, undefined, undefined], - [1, undefined, 3, undefined, 5, 6, 7, 8, undefined, undefined], - [1, 0, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined] + [undefined, undefined, undefined, 4, 5, 6], + [1, undefined, 3, undefined, 5, 6, 7, 8], + [1, 0, undefined] ] ); }); @@ -195,10 +177,43 @@ describe('Chartist core', function() { }] }; - expect(Chartist.normalizeDataArray(Chartist.getDataArray(data))).toEqual( + expect(Chartist.getDataArray(data)).toEqual( [[1, 4, 2, 7, 2, 0]] ); }); + + it('should normalize correctly with mixed dimensional input into multi dimensional output', function() { + var data = { + labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + series: [{ + data: [ + { value: 1 }, + { value: {y: 4, x: 1}}, + { y: 2, x: 2}, + NaN, + null, + { value: 7 }, + { value: 2 }, + { value: null }, + { y: undefined, x: NaN } + ] + }] + }; + + expect(Chartist.getDataArray(data, false, true)).toEqual( + [[ + {x: undefined, y: 1}, + {x: 1, y: 4}, + {x: 2, y: 2}, + undefined, + undefined, + {x: undefined, y: 7}, + {x: undefined, y: 2}, + undefined, + {x: undefined, y: undefined} + ]] + ); + }); }); describe('padding normalization tests', function () { diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index 737eccb8..c16ddf72 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -117,12 +117,12 @@ describe('Line chart tests', function () { data: pathElement.data }; })).toEqual([ - {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, - {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, - {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, - {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, - {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, - {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} ]); done(); } @@ -149,14 +149,14 @@ describe('Line chart tests', function () { data: pathElement.data }; })).toEqual([ - {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, // Cardinal should create Line path segment if only one connection - {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, - {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, // Cardinal should create Curve path segment for 2 or more connections - {command: 'C', data: {valueIndex: 5, value: 3, meta: undefined}}, - {command: 'C', data: {valueIndex: 6, value: 4, meta: undefined}}, - {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + {command: 'C', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} ]); done(); } @@ -183,12 +183,12 @@ describe('Line chart tests', function () { data: pathElement.data }; })).toEqual([ - {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, - {command: 'C', data: {valueIndex: 2, value: 0, meta: undefined}}, - {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, - {command: 'C', data: {valueIndex: 5, value: 3, meta: undefined}}, - {command: 'C', data: {valueIndex: 6, value: 4, meta: undefined}}, - {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'C', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'C', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} ]); done(); } @@ -215,15 +215,15 @@ describe('Line chart tests', function () { data: pathElement.data }; })).toEqual([ - {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, - {command: 'L', data: {valueIndex: 1, value: 15, meta: undefined}}, - {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, - {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, - {command: 'L', data: {valueIndex: 4, value: 2, meta: undefined}}, - {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, - {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, - {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, - {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} ]); done(); } @@ -252,15 +252,15 @@ describe('Line chart tests', function () { data: pathElement.data }; })).toEqual([ - {command: 'M', data: {valueIndex: 1, value: 15, meta: undefined}}, - {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, - {command: 'L', data: {valueIndex: 2, value: 0, meta: undefined}}, - {command: 'M', data: {valueIndex: 4, value: 2, meta: undefined}}, - {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, - {command: 'L', data: {valueIndex: 5, value: 3, meta: undefined}}, - {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, - {command: 'L', data: {valueIndex: 6, value: 4, meta: undefined}}, - {command: 'M', data: {valueIndex: 8, value: 1, meta: 'meta data'}} + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} ]); done(); } From 0d0267b42cc9a9d7e45c12c5d82e286284e5ca3b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 9 Jun 2015 23:01:53 +0200 Subject: [PATCH 272/593] doc: Fixed issue with auto-indent of handlebars 3 --- site/templates/api-documentation.hbs | 3 ++- site/templates/examples.hbs | 3 ++- site/templates/getting-started.hbs | 3 ++- site/templates/index.hbs | 1 + site/templates/plugins.hbs | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/site/templates/api-documentation.hbs b/site/templates/api-documentation.hbs index 688435e2..66732954 100644 --- a/site/templates/api-documentation.hbs +++ b/site/templates/api-documentation.hbs @@ -4,7 +4,8 @@ side-nav: api-side-navigation page-class: api-documentation title: Chartist - API Documentation description: Detailed documentation of the Chartist.js code and API +preventIndent: true --- {{#each (doxTransform apidox)}} {{>dox-section}} -{{/each}} \ No newline at end of file +{{/each}} diff --git a/site/templates/examples.hbs b/site/templates/examples.hbs index 8c0fb1d4..6f1f230a 100644 --- a/site/templates/examples.hbs +++ b/site/templates/examples.hbs @@ -3,7 +3,8 @@ layout: content page-class: examples title: Chartist - Examples description: Demos and examples of Chartist.js with live editing functionality +preventIndent: true --- {{#each page.sections}} {{>section}} -{{/each}} \ No newline at end of file +{{/each}} diff --git a/site/templates/getting-started.hbs b/site/templates/getting-started.hbs index f417c7a0..7e0e2816 100644 --- a/site/templates/getting-started.hbs +++ b/site/templates/getting-started.hbs @@ -3,7 +3,8 @@ layout: content page-class: getting-started title: Chartist - Getting started description: Learn how to use Chartist.js +preventIndent: true --- {{#each page.sections}} {{>section}} -{{/each}} \ No newline at end of file +{{/each}} diff --git a/site/templates/index.hbs b/site/templates/index.hbs index fc801d5b..88b80648 100644 --- a/site/templates/index.hbs +++ b/site/templates/index.hbs @@ -3,6 +3,7 @@ layout: landing page-class: full title: Chartist - Simple responsive charts description: Create responsive, scalable and good looking charts with chartist.js. +preventIndent: true ---

    You may think that this is just yet an other charting library. But Chartist.js is the product of a community that was disappointed about the abilities provided by other charting libraries. Of course there are hundreds diff --git a/site/templates/plugins.hbs b/site/templates/plugins.hbs index a5a76e3b..f4daf97d 100644 --- a/site/templates/plugins.hbs +++ b/site/templates/plugins.hbs @@ -3,6 +3,7 @@ layout: content page-class: plugins title: Chartist - Plugins description: Use plugins to extend the functionality of your charts +preventIndent: true --- {{#each page.sections}} {{>section}} From 86d34bd4dcc2f9471614606a47e89233d18bf535 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 10 Jun 2015 00:13:31 +0200 Subject: [PATCH 273/593] Renamed axes and updated jsdoc --- site/layouts/default.hbs | 4 +- src/scripts/axes/auto-scale-axis.js | 47 +++++++++++++++++++ src/scripts/axes/axis.js | 5 -- ...continuous-axis.js => fixed-scale-axis.js} | 17 ++++--- src/scripts/axes/linear-scale-axis.js | 31 ------------ src/scripts/axes/step-axis.js | 12 ++++- src/scripts/charts/bar.js | 4 +- src/scripts/charts/line.js | 14 ++---- src/scripts/core.js | 4 +- tasks/concat.js | 4 +- tasks/jasmine.js | 3 +- 11 files changed, 82 insertions(+), 63 deletions(-) create mode 100644 src/scripts/axes/auto-scale-axis.js rename src/scripts/axes/{continuous-axis.js => fixed-scale-axis.js} (76%) delete mode 100644 src/scripts/axes/linear-scale-axis.js diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 3846dc06..2bf421dd 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -61,9 +61,9 @@ - + + - diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js new file mode 100644 index 00000000..ebc402aa --- /dev/null +++ b/src/scripts/axes/auto-scale-axis.js @@ -0,0 +1,47 @@ +/** + * 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. + * **Options** + * 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. + * ```javascript + * var options = { + * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored + * high: 100, + * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored + * low: 0, + * // 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). + * scaleMinSpace: 20, + * // Can be set to true or false. If set to true, the scale will be generated with whole numbers only. + * onlyInteger: true, + * // 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. + * referenceValue: 5 + * }; + * ``` + * + * @module Chartist.AutoScaleAxis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + function AutoScaleAxis(axisUnit, data, chartRect, options) { + // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options + this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + + Chartist.AutoScaleAxis.super.constructor.call(this, + axisUnit, + chartRect, + this.bounds.values, + options); + } + + function projectValue(value) { + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; + } + + Chartist.AutoScaleAxis = Chartist.Axis.extend({ + constructor: AutoScaleAxis, + projectValue: projectValue + }); + +}(window, document, Chartist)); diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 9e498343..4ea910a5 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -1,8 +1,3 @@ -/** - * Axis base class used to implement different axis types - * - * @module Chartist.Axis - */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; diff --git a/src/scripts/axes/continuous-axis.js b/src/scripts/axes/fixed-scale-axis.js similarity index 76% rename from src/scripts/axes/continuous-axis.js rename to src/scripts/axes/fixed-scale-axis.js index c4ede83d..e2311564 100644 --- a/src/scripts/axes/continuous-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -1,9 +1,8 @@ /** - * The continuous axis uses standard linear continuous 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. - * - * *options* + * 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. + * **Options** * 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. - * ``` + * ```javascript * var options = { * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored * high: 100, @@ -16,20 +15,20 @@ * }; * ``` * - * @module Chartist.ContinuousAxis + * @module Chartist.FixedScaleAxis */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; - function ContinuousAxis(axisUnit, data, chartRect, options) { + function FixedScaleAxis(axisUnit, data, chartRect, options) { this.highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return this.highLow.low + (this.highLow.high - this.highLow.low) / this.divisor * index; }.bind(this)); - Chartist.ContinuousAxis.super.constructor.call(this, + Chartist.FixedScaleAxis.super.constructor.call(this, axisUnit, chartRect, this.ticks, @@ -42,8 +41,8 @@ return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.highLow.low) / (this.highLow.high - this.highLow.low); } - Chartist.ContinuousAxis = Chartist.Axis.extend({ - constructor: ContinuousAxis, + Chartist.FixedScaleAxis = Chartist.Axis.extend({ + constructor: FixedScaleAxis, projectValue: projectValue }); diff --git a/src/scripts/axes/linear-scale-axis.js b/src/scripts/axes/linear-scale-axis.js deleted file mode 100644 index 554cebeb..00000000 --- a/src/scripts/axes/linear-scale-axis.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * The linear scale axis uses standard linear scale projection of values along an axis. - * - * @module Chartist.LinearScaleAxis - */ -/* global Chartist */ -(function (window, document, Chartist) { - 'use strict'; - - function LinearScaleAxis(axisUnit, data, chartRect, options) { - // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options - this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); - this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger); - - Chartist.LinearScaleAxis.super.constructor.call(this, - axisUnit, - chartRect, - this.bounds.values, - options); - } - - function projectValue(value) { - return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; - } - - Chartist.LinearScaleAxis = Chartist.Axis.extend({ - constructor: LinearScaleAxis, - projectValue: projectValue - }); - -}(window, document, Chartist)); diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index 369b8d35..383728d7 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -1,5 +1,15 @@ /** - * Step axis for step based charts like bar chart or step based line chart + * 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 while 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. + * **Options** + * 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. + * ```javascript + * var options = { + * // 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. + * ticks: ['One', 'Two', 'Three'], + * // 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. + * stretch: true + * }; + * ``` * * @module Chartist.StepAxis */ diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 35b26075..963e7da8 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -168,7 +168,7 @@ ticks: labelAxisTicks }); - valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, referenceValue: 0 })); @@ -177,7 +177,7 @@ ticks: labelAxisTicks }); - valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 1e2fd275..aada2b17 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -32,12 +32,8 @@ showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, - // Set the axis type to be used to project values on this axis - type: Chartist.Axis.StepAxis, - // This value specifies the minimum height in pixel of the scale steps - scaleMinSpace: 20, - // Use only integer values (whole numbers) for the scale steps - onlyInteger: false + // 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. + type: undefined }, // Options for Y-Axis axisY: { @@ -56,8 +52,8 @@ showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, - // Set the axis type to be used to project values on this axis - type: Chartist.Axis.LinearScaleAxis, + // 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. + type: undefined, // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20, // Use only integer values (whole numbers) for the scale steps @@ -140,7 +136,7 @@ } if(options.axisY.type === undefined) { - axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { high: Chartist.isNum(options.high) ? options.high : options.axisY.high, low: Chartist.isNum(options.low) ? options.low : options.axisY.low })); diff --git a/src/scripts/core.js b/src/scripts/core.js index 455162e6..12f9f006 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -477,7 +477,9 @@ var Chartist = { } // Start to find highest and lowest number recursively - recursiveHighLow(data); + if(findHigh || findLow) { + recursiveHighLow(data); + } // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity diff --git a/tasks/concat.js b/tasks/concat.js index 87f3755f..f2ad81c9 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -26,9 +26,9 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/scripts/svg.js', '<%= pkg.config.src %>/scripts/svg-path.js', '<%= pkg.config.src %>/scripts/axes/axis.js', - '<%= pkg.config.src %>/scripts/axes/linear-scale-axis.js', + '<%= pkg.config.src %>/scripts/axes/auto-scale-axis.js', + '<%= pkg.config.src %>/scripts/axes/fixed-scale-axis.js', '<%= pkg.config.src %>/scripts/axes/step-axis.js', - '<%= pkg.config.src %>/scripts/axes/continuous-axis.js', '<%= pkg.config.src %>/scripts/charts/line.js', '<%= pkg.config.src %>/scripts/charts/bar.js', '<%= pkg.config.src %>/scripts/charts/pie.js' diff --git a/tasks/jasmine.js b/tasks/jasmine.js index f3b7f4ce..c3fe2904 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -22,7 +22,8 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/scripts/svg-path.js', '<%= pkg.config.src %>/scripts/axes/axis.js', '<%= pkg.config.src %>/scripts/axes/step-axis.js', - '<%= pkg.config.src %>/scripts/axes/linear-scale-axis.js', + '<%= pkg.config.src %>/scripts/axes/auto-scale-axis.js', + '<%= pkg.config.src %>/scripts/axes/fixed-scale-axis.js', '<%= pkg.config.src %>/scripts/charts/line.js', '<%= pkg.config.src %>/scripts/charts/bar.js', '<%= pkg.config.src %>/scripts/charts/pie.js' From afa1816565f3dee06bd768dde83bc23aa3ab8280 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 10 Jun 2015 02:21:49 +0200 Subject: [PATCH 274/593] Fixed issue with value objects exposed on attributes --- src/scripts/charts/line.js | 6 ++---- src/scripts/core.js | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index aada2b17..a880a83e 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -204,7 +204,7 @@ x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': pathElement.data.value, + 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y, 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); @@ -226,9 +226,7 @@ if(seriesOptions.showLine) { var line = seriesElement.elem('path', { d: path.stringify() - }, options.classNames.line, true).attr({ - 'values': data.normalized[seriesIndex] - }, Chartist.xmlNs.uri); + }, options.classNames.line, true); this.eventEmitter.emit('draw', { type: 'line', diff --git a/src/scripts/core.js b/src/scripts/core.js index 12f9f006..c927d11e 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -543,9 +543,9 @@ var Chartist = { if(Chartist.isNum(value)) { return +value; } else if(value) { - return value[dimension]; + return value[dimension] || 0; } else { - return undefined; + return 0; } }; From 2cb43b412cf4b2f5da448b6d83477f1cafa0e411 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 10 Jun 2015 02:23:14 +0200 Subject: [PATCH 275/593] Relying on highLow from axis for area drawing --- src/scripts/charts/line.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index a880a83e..a2ee2231 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -241,10 +241,11 @@ }); } - if(seriesOptions.showArea) { + // Area currently only works with axes that support highLow! + if(seriesOptions.showArea && axisY.highLow) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); + var areaBase = Math.max(Math.min(options.areaBase, axisY.highLow.high), axisY.highLow.low); // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); From 155564ae21de49999dc19daa32a4c89574706f2f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 10 Jun 2015 02:24:38 +0200 Subject: [PATCH 276/593] Throwing up in infinite loop for edge cases and during development --- src/scripts/core.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/scripts/core.js b/src/scripts/core.js index c927d11e..9fab8d1a 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -600,6 +600,7 @@ var Chartist = { */ Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue, onlyInteger) { var i, + optimizationCounter = 0, newMin, newMax, bounds = { @@ -651,6 +652,10 @@ var Chartist = { } else { break; } + + if(optimizationCounter++ > 1000) { + throw new Error('Exceeded maximum number of iterations while optimizing scale step!'); + } } } From 813a8e2811bd6390700386152dff7e36c2eb1831 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 10 Jun 2015 02:25:24 +0200 Subject: [PATCH 277/593] doc: Added documentation for custom axis configuration --- site/code-snippets/1-dimension-values.js | 4 + site/code-snippets/2-dimensions-values.js | 8 ++ site/data/pages/getting-started.yml | 118 +++++++++++++++++++ site/examples/example-axis-auto.js | 14 +++ site/examples/example-axis-fixed-and-auto.js | 21 ++++ 5 files changed, 165 insertions(+) create mode 100644 site/code-snippets/1-dimension-values.js create mode 100644 site/code-snippets/2-dimensions-values.js create mode 100644 site/examples/example-axis-auto.js create mode 100644 site/examples/example-axis-fixed-and-auto.js diff --git a/site/code-snippets/1-dimension-values.js b/site/code-snippets/1-dimension-values.js new file mode 100644 index 00000000..18177c91 --- /dev/null +++ b/site/code-snippets/1-dimension-values.js @@ -0,0 +1,4 @@ +var data = { + labels: ['A', 'B', 'C'], + series: [[10, 8, 14]] +}; diff --git a/site/code-snippets/2-dimensions-values.js b/site/code-snippets/2-dimensions-values.js new file mode 100644 index 00000000..f28adaef --- /dev/null +++ b/site/code-snippets/2-dimensions-values.js @@ -0,0 +1,8 @@ +var data = { + labels: ['A', 'B', 'C'], + series: [[ + {x: undefined, y: 10}, + {x: undefined, y: 8}, + {x: undefined, y: 14} + ]] +}; diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index b3060887..1fedee37 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -633,3 +633,121 @@ sections: classes: ct-golden-section intro: > Edit this example to figure out how to tweak animations. The force is strong in you young padawan! + + - type: sub-section + data: + title: Switching axis type + level: 4 + items: + - type: text + data: + text: > + The default configuration of the line chart is that it will use a step based X-Axis and an + automatic linear scale for the Y-Axis. This is all happening under the hood of Chartist and + already satisfies a lot of use-cases. + - type: text + data: + text: > + Sometimes though, it's not enough to have a fixed step chart and you'd need something a bit + more complex. Something that allows you to plot those values along the X- and Y-Axis, instead + of just the Y-Axis. Sometimes, you'd also want to specify the ticks on your chart manually + rather than having them auto calculated from Chartist. + - type: text + data: + text: > + Of course Chartist wouldn't let you down with all those ideas you have in mind on how to + visualize your data! + + - type: sub-section + data: + title: A line chart is only 1-dimensional?! + level: 5 + items: + - type: text + data: + text: > + By default, Chartist uses Chartist.StepAxis for the X-Axis and Chartist.AutoScaleAxis + for the Y-Axis. Please read the API documentation + if you'd like to get more details, or available options on axis configuration. + - type: text + data: + text: > + The step based axis will not use any value for projection but rather rely on the index + of the given value to determine the position. This is fine for discrete steps of one + dimensional data, like we know it from regular Chartist charts: + - type: code-snippet + data: + id: 1-dimension-values + lang: js + - type: text + data: + text: > + What really happens with such one dimensional series data under the hood is that it will + be transformed into two dimensional data like so: + - type: code-snippet + data: + id: 2-dimensions-values + lang: js + - type: text + data: + text: > + You can see that Chartist will automatically convert one dimensional data into two + dimensional values where the previous value is assigned to y and x will be set to + undefined. As the default axis for projecting the x value + is a Chartist.StepAxis that relies on the value index rather than the + value, this is perfectly fine for the default setup. + + + - type: sub-section + data: + title: Creating an XY-plot chart + level: 5 + items: + - type: text + data: + text: > + In order to plot on the X-Axis too, we'd need to switch the standard axis type + Chartist.StepAxis to something more continuous. Let's create a full fledged auto + scale chart that scales both the Y- and X-Axis automatically using + the Chartist.AutoScaleAxis! + - type: live-example + data: + title: Configure your axis type + level: 6 + id: example-axis-auto + classes: ct-golden-section + intro: > + Note that we have just specified the X-Axis because the Y-Axis is configured to + Chartist.AutoScaleAxis by default. + - type: text + data: + text: > + A few things are different in this chart. Because + the labels array of our data is just used to be mapped as ticks option for the + default Chartist.StepAxis X-Axis, we can completely remove the labels from our data, + once we use a different axis than the step based one. Also you can see now from the + data series is that we are specifying 2-dimensional values directly. + + - type: sub-section + data: + title: Fixed stuff can be sweet too! + level: 5 + items: + - type: text + data: + text: > + The following example shows how to create an axis with some fixed ticks. + The Chartist.FixedScaleAxis can be used to create a more rudimentary + continuous linear scale, where ticks can be fixed either with an array of values or + with a divisor. For the detailed options please check + the API documentation. + - type: live-example + data: + title: Unleash your creativity... + level: 6 + id: example-axis-fixed-and-auto + classes: ct-golden-section + intro: > + Let's say we'd like to fix a few ticks on the Y-Axis on our chart as those are the only + ones we're interested in. The X-Axis should be continuous too, but let's make + that axis a Chartist.AutoScaleAxis. diff --git a/site/examples/example-axis-auto.js b/site/examples/example-axis-auto.js new file mode 100644 index 00000000..cc2a0b6c --- /dev/null +++ b/site/examples/example-axis-auto.js @@ -0,0 +1,14 @@ +new Chartist.Line('.ct-chart', { + series: [[ + {x: 1, y: 100}, + {x: 2, y: 50}, + {x: 3, y: 25}, + {x: 5, y: 12.5}, + {x: 8, y: 6.25} + ]] +}, { + axisX: { + type: Chartist.AutoScaleAxis, + onlyInteger: true + } +}); diff --git a/site/examples/example-axis-fixed-and-auto.js b/site/examples/example-axis-fixed-and-auto.js new file mode 100644 index 00000000..3638693a --- /dev/null +++ b/site/examples/example-axis-fixed-and-auto.js @@ -0,0 +1,21 @@ +new Chartist.Line('.ct-chart', { + series: [[ + {x: 1, y: 100}, + {x: 2, y: 50}, + {x: 3, y: 25}, + {x: 5, y: 12.5}, + {x: 8, y: 6.25} + ]] +}, { + axisX: { + type: Chartist.AutoScaleAxis, + onlyInteger: true + }, + axisY: { + type: Chartist.FixedScaleAxis, + ticks: [0, 50, 75, 87.5, 100], + low: 0 + }, + lineSmooth: Chartist.Interpolation.step(), + showPoint: false +}); From ad6818233396c75d72f8bd64b7cb4c7b75cbcc8e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 10 Jun 2015 11:14:47 +0200 Subject: [PATCH 278/593] Added areaBase to series options override in line chart, fixes #342 --- src/scripts/charts/line.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index a2ee2231..16d15cff 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -183,7 +183,8 @@ lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'), showPoint: Chartist.getSeriesOption(series, options, 'showPoint'), showLine: Chartist.getSeriesOption(series, options, 'showLine'), - showArea: Chartist.getSeriesOption(series, options, 'showArea') + showArea: Chartist.getSeriesOption(series, options, 'showArea'), + areaBase: Chartist.getSeriesOption(series, options, 'areaBase') }; var smoothing = typeof seriesOptions.lineSmooth === 'function' ? @@ -245,7 +246,7 @@ if(seriesOptions.showArea && axisY.highLow) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, axisY.highLow.high), axisY.highLow.low); + var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.highLow.high), axisY.highLow.low); // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); From 45df861eb65f98a00b6c4f2ed4f6a9f37bd20265 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 10 Jun 2015 11:24:01 +0200 Subject: [PATCH 279/593] Distribution of 0.9.0 --- CHANGELOG.md | 7 + bower.json | 2 +- dist/chartist.js | 652 ++++++++++++++++++++++----------------- dist/chartist.min.js | 6 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- 6 files changed, 388 insertions(+), 283 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd89441..d8ff34d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v0.9.0 - 10 Jun 2015 +-------------------- +- Major refactoring of axis and projection code, added possibility to configure axes when creating a chart +- Added areaBase to series options override in line chart, fixes #342 +- Throwing up in infinite loop for edge cases and during development +- Documentation: Added documentation for axis configuration and getting started guide for custom axes + v0.8.3 - 07 Jun 2015 -------------------- - Greatly reduced CSS selector complexity and split slice into slice-pie and slice-donut diff --git a/bower.json b/bower.json index 0abfd55b..6fe297cf 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chartist", - "version": "0.8.3", + "version": "0.9.0", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" diff --git a/dist/chartist.js b/dist/chartist.js index 4ba8c3bd..d6668769 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.8.3 +/* Chartist.js 0.9.0 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.8.3' + version: '0.9.0' }; (function (window, document, Chartist) { @@ -352,9 +352,10 @@ var Chartist = { * @memberof Chartist.Core * @param {Object} data The series object that contains the data to be visualized in the chart * @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. + * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ - Chartist.getDataArray = function (data, reverse) { + Chartist.getDataArray = function (data, reverse, multi) { // If the data should be reversed but isn't we need to reverse it // If it's reversed but it shouldn't we need to reverse it back // That's required to handle data updates correctly and to reflect the responsive configurations @@ -363,17 +364,27 @@ var Chartist = { data.reversed = !data.reversed; } - // Rcursively walks through nested arrays and convert string values to numbers and objects with value properties + // Recursively walks through nested arrays and convert string values to numbers and objects with value properties // to values. Check the tests in data core -> data normalization for a detailed specification of expected values function recursiveConvert(value) { - if(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) { + if(Chartist.isFalseyButZero(value)) { + // This is a hole in data and we should return undefined return undefined; } else if((value.data || value) instanceof Array) { return (value.data || value).map(recursiveConvert); } else if(value.hasOwnProperty('value')) { return recursiveConvert(value.value); } else { - return +value; + if(multi) { + return { + x: Chartist.getNumberOrUndefined(value.x), + // Single series value arrays are assumed to specify the Y-Axis value + // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] + y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value) + }; + } else { + return Chartist.getNumberOrUndefined(value); + } } } @@ -404,28 +415,6 @@ var Chartist = { }; }; - /** - * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart - * - * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function. - * @param {Number} length The length of the x-axis data array. - * @return {Array} The array that got updated with missing values. - */ - Chartist.normalizeDataArray = function (dataArray, length) { - for (var i = 0; i < dataArray.length; i++) { - if (dataArray[i].length === length) { - continue; - } - - for (var j = dataArray[i].length; j < length; j++) { - dataArray[i][j] = undefined; - } - } - - return dataArray; - }; - Chartist.getMetaData = function(series, index) { var value = series.data ? series.data[index] : series[index]; return value ? Chartist.serialize(value.meta) : undefined; @@ -471,11 +460,15 @@ var Chartist = { * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. * * @memberof Chartist.Core - * @param {Array} dataArray The array that contains the data to be visualized in the chart + * @param {Array} data The array that contains the data to be visualized in the chart * @param {Object} options The Object that contains all the optional values for the chart + * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ - Chartist.getHighLow = function (dataArray, options) { + Chartist.getHighLow = function (data, options, dimension) { + // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred + options = Chartist.extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {}); + var highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low @@ -485,23 +478,29 @@ var Chartist = { // Function to recursively walk through arrays and find highest and lowest number function recursiveHighLow(data) { - if(data instanceof Array) { + if(data === undefined) { + return undefined; + } else if(data instanceof Array) { for (var i = 0; i < data.length; i++) { recursiveHighLow(data[i]); } } else { - if (findHigh && data > highLow.high) { - highLow.high = data; + var value = dimension ? +data[dimension] : +data; + + if (findHigh && value > highLow.high) { + highLow.high = value; } - if (findLow && data < highLow.low) { - highLow.low = data; + if (findLow && value < highLow.low) { + highLow.low = value; } } } // Start to find highest and lowest number recursively - recursiveHighLow(dataArray); + if(findHigh || findLow) { + recursiveHighLow(data); + } // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity @@ -521,6 +520,56 @@ var Chartist = { return highLow; }; + /** + * Checks if the value is a valid number or string with a number. + * + * @memberof Chartist.Core + * @param value + * @returns {Boolean} + */ + Chartist.isNum = function(value) { + return !isNaN(value) && isFinite(value); + }; + + /** + * Returns true on all falsey values except the numeric value 0. + * + * @memberof Chartist.Core + * @param value + * @returns {boolean} + */ + Chartist.isFalseyButZero = function(value) { + return !value && value !== 0; + }; + + /** + * 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. + * + * @memberof Chartist.Core + * @param value + * @returns {*} + */ + Chartist.getNumberOrUndefined = function(value) { + return isNaN(+value) ? undefined : +value; + }; + + /** + * 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 undefined. + * + * @param value + * @param dimension + * @returns {*} + */ + Chartist.getMultiValue = function(value, dimension) { + if(Chartist.isNum(value)) { + return +value; + } else if(value) { + return value[dimension] || 0; + } else { + return 0; + } + }; + /** * 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. * @@ -572,6 +621,7 @@ var Chartist = { */ Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue, onlyInteger) { var i, + optimizationCounter = 0, newMin, newMax, bounds = { @@ -623,6 +673,10 @@ var Chartist = { } else { break; } + + if(optimizationCounter++ > 1000) { + throw new Error('Exceeded maximum number of iterations while optimizing scale step!'); + } } } @@ -728,7 +782,7 @@ var Chartist = { * Creates a grid line based on a projected value. * * @memberof Chartist.Core - * @param projectedValue + * @param position * @param index * @param axis * @param offset @@ -737,10 +791,10 @@ var Chartist = { * @param classes * @param eventEmitter */ - Chartist.createGrid = function(projectedValue, index, axis, offset, length, group, classes, eventEmitter) { + Chartist.createGrid = function(position, index, axis, offset, length, group, classes, eventEmitter) { var positionalData = {}; - positionalData[axis.units.pos + '1'] = projectedValue.pos; - positionalData[axis.units.pos + '2'] = projectedValue.pos; + positionalData[axis.units.pos + '1'] = position; + positionalData[axis.units.pos + '2'] = position; positionalData[axis.counterUnits.pos + '1'] = offset; positionalData[axis.counterUnits.pos + '2'] = offset + length; @@ -762,7 +816,8 @@ var Chartist = { * Creates a label based on a projected value and an axis. * * @memberof Chartist.Core - * @param projectedValue + * @param position + * @param length * @param index * @param labels * @param axis @@ -773,13 +828,13 @@ var Chartist = { * @param useForeignObject * @param eventEmitter */ - Chartist.createLabel = function(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + Chartist.createLabel = function(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { var labelElement; var positionalData = {}; - positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos]; + positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; - positionalData[axis.units.len] = projectedValue.len; + positionalData[axis.units.len] = length; positionalData[axis.counterUnits.len] = axisOffset - 10; if(useForeignObject) { @@ -807,78 +862,6 @@ var Chartist = { }, positionalData)); }; - /** - * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect. - * - * @memberof Chartist.Core - * @param axis - * @param data - * @param chartRect - * @param gridGroup - * @param labelGroup - * @param useForeignObject - * @param options - * @param eventEmitter - */ - Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) { - var axisOptions = options['axis' + axis.units.pos.toUpperCase()]; - var projectedValues = data.map(axis.projectValue.bind(axis)); - var labelValues = data.map(axisOptions.labelInterpolationFnc); - - projectedValues.forEach(function(projectedValue, index) { - var labelOffset = { - x: 0, - y: 0 - }; - - // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!labelValues[index] && labelValues[index] !== 0) { - return; - } - - // Transform to global coordinates using the chartRect - // We also need to set the label offset for the createLabel function - if(axis.units.pos === 'x') { - projectedValue.pos = chartRect.x1 + projectedValue.pos; - labelOffset.x = options.axisX.labelOffset.x; - - // If the labels should be positioned in start position (top side for vertical axis) we need to set a - // different offset as for positioned with end (bottom) - if(options.axisX.position === 'start') { - labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); - } else { - labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20); - } - } else { - projectedValue.pos = chartRect.y1 - projectedValue.pos; - labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 0); - - // If the labels should be positioned in start position (left side for horizontal axis) we need to set a - // different offset as for positioned with end (right side) - if(options.axisY.position === 'start') { - labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10; - } else { - labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10; - } - } - - if(axisOptions.showGrid) { - Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [ - options.classNames.grid, - options.classNames[axis.units.dir] - ], eventEmitter); - } - - if(axisOptions.showLabel) { - Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [ - options.classNames.label, - options.classNames[axis.units.dir], - options.classNames[axisOptions.position] - ], useForeignObject, eventEmitter); - } - }); - }; - /** * Helper to read series specific options from options object. It automatically falls back to the global option if * there is no option in the series options. @@ -2656,12 +2639,7 @@ var Chartist = { Chartist.Svg.Path.elementDescriptions = elementDescriptions; Chartist.Svg.Path.join = join; }(window, document, Chartist)); -;/** - * Axis base class used to implement different axis types - * - * @module Chartist.Axis - */ -/* global Chartist */ +;/* global Chartist */ (function (window, document, Chartist) { 'use strict'; @@ -2684,17 +2662,91 @@ var Chartist = { } }; - function Axis(units, chartRect, options) { + function Axis(units, chartRect, ticks, options) { this.units = units; this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; this.chartRect = chartRect; this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; this.gridOffset = chartRect[units.rectOffset]; + this.ticks = ticks; this.options = options; } + function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) { + var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; + var projectedValues = this.ticks.map(this.projectValue.bind(this)); + var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); + + projectedValues.forEach(function(projectedValue, index) { + var labelOffset = { + x: 0, + y: 0 + }; + + // TODO: Find better solution for solving this problem + // Calculate how much space we have available for the label + var labelLength; + if(projectedValues[index + 1]) { + // If we still have one label ahead, we can calculate the distance to the next tick / label + labelLength = projectedValues[index + 1] - projectedValue; + } else { + // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to + // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will + // still be visible inside of the chart padding. + labelLength = Math.max(this.axisLength - projectedValue, 30); + } + + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + if(!labelValues[index] && labelValues[index] !== 0) { + return; + } + + // Transform to global coordinates using the chartRect + // We also need to set the label offset for the createLabel function + if(this.units.pos === 'x') { + projectedValue = this.chartRect.x1 + projectedValue; + labelOffset.x = chartOptions.axisX.labelOffset.x; + + // If the labels should be positioned in start position (top side for vertical axis) we need to set a + // different offset as for positioned with end (bottom) + if(chartOptions.axisX.position === 'start') { + labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } else { + labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } + } else { + projectedValue = this.chartRect.y1 - projectedValue; + labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0); + + // If the labels should be positioned in start position (left side for horizontal axis) we need to set a + // different offset as for positioned with end (right side) + if(chartOptions.axisY.position === 'start') { + labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10; + } else { + labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; + } + } + + if(axisOptions.showGrid) { + Chartist.createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [ + chartOptions.classNames.grid, + chartOptions.classNames[this.units.dir] + ], eventEmitter); + } + + if(axisOptions.showLabel) { + Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [ + chartOptions.classNames.label, + chartOptions.classNames[this.units.dir], + chartOptions.classNames[axisOptions.position] + ], useForeignObject, eventEmitter); + } + }.bind(this)); + } + Chartist.Axis = Chartist.Class.extend({ constructor: Axis, + createGridAndLabels: createGridAndLabels, projectValue: function(value, index, data) { throw new Error('Base axis can\'t be instantiated!'); } @@ -2704,38 +2756,113 @@ var Chartist = { }(window, document, Chartist)); ;/** - * The linear scale axis uses standard linear scale projection of values along an axis. + * 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. + * **Options** + * 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. + * ```javascript + * var options = { + * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored + * high: 100, + * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored + * low: 0, + * // 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). + * scaleMinSpace: 20, + * // Can be set to true or false. If set to true, the scale will be generated with whole numbers only. + * onlyInteger: true, + * // 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. + * referenceValue: 5 + * }; + * ``` * - * @module Chartist.LinearScaleAxis + * @module Chartist.AutoScaleAxis */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; - function LinearScaleAxis(axisUnit, chartRect, options) { - Chartist.LinearScaleAxis.super.constructor.call(this, + function AutoScaleAxis(axisUnit, data, chartRect, options) { + // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options + this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + + Chartist.AutoScaleAxis.super.constructor.call(this, axisUnit, chartRect, + this.bounds.values, options); + } - this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger); + function projectValue(value) { + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; + } + + Chartist.AutoScaleAxis = Chartist.Axis.extend({ + constructor: AutoScaleAxis, + projectValue: projectValue + }); + +}(window, document, Chartist)); +;/** + * 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. + * **Options** + * 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. + * ```javascript + * var options = { + * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored + * high: 100, + * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored + * low: 0, + * // 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. + * divisor: 4, + * // 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. + * ticks: [1, 10, 20, 30] + * }; + * ``` + * + * @module Chartist.FixedScaleAxis + */ +/* global Chartist */ +(function (window, document, Chartist) { + 'use strict'; + + function FixedScaleAxis(axisUnit, data, chartRect, options) { + this.highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); + this.divisor = options.divisor || 1; + this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { + return this.highLow.low + (this.highLow.high - this.highLow.low) / this.divisor * index; + }.bind(this)); + + Chartist.FixedScaleAxis.super.constructor.call(this, + axisUnit, + chartRect, + this.ticks, + options); + + this.stepLength = this.axisLength / this.divisor; } function projectValue(value) { - return { - pos: this.axisLength * (value - this.bounds.min) / this.bounds.range, - len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds) - }; + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.highLow.low) / (this.highLow.high - this.highLow.low); } - Chartist.LinearScaleAxis = Chartist.Axis.extend({ - constructor: LinearScaleAxis, + Chartist.FixedScaleAxis = Chartist.Axis.extend({ + constructor: FixedScaleAxis, projectValue: projectValue }); }(window, document, Chartist)); ;/** - * Step axis for step based charts like bar chart or step based line chart + * 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 while 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. + * **Options** + * 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. + * ```javascript + * var options = { + * // 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. + * ticks: ['One', 'Two', 'Three'], + * // 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. + * stretch: true + * }; + * ``` * * @module Chartist.StepAxis */ @@ -2743,20 +2870,18 @@ var Chartist = { (function (window, document, Chartist) { 'use strict'; - function StepAxis(axisUnit, chartRect, options) { + function StepAxis(axisUnit, data, chartRect, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, chartRect, + options.ticks, options); - this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0)); + this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0)); } function projectValue(value, index) { - return { - pos: this.stepLength * index, - len: this.stepLength - }; + return this.stepLength * index; } Chartist.StepAxis = Chartist.Axis.extend({ @@ -2799,8 +2924,8 @@ var Chartist = { showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, - // Use only integer values (whole numbers) for the scale steps - onlyInteger: false + // 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. + type: undefined }, // Options for Y-Axis axisY: { @@ -2819,6 +2944,8 @@ var Chartist = { showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, + // 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. + type: undefined, // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20, // Use only integer values (whole numbers) for the scale steps @@ -2876,64 +3003,54 @@ var Chartist = { * */ function createChart(options) { - var seriesGroups = []; - var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length); + var data = { + raw: this.data, + normalized: Chartist.getDataArray(this.data, options.reverseData, true) + }; // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); + // Create groups for labels, grid and series + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); - var highLow = Chartist.getHighLow(normalizedData, options); - - var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { - stepCount: this.data.labels.length, - stretch: options.fullWidth - }); + var axisX, axisY; - var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { - highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - onlyInteger: options.axisY.onlyInteger - }); - - // Start drawing - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), - gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + if(options.axisX.type === undefined) { + axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + ticks: data.raw.labels, + stretch: options.fullWidth + })); + } else { + axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + } - Chartist.createAxis( - axisX, - this.data.labels, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); + if(options.axisY.type === undefined) { + axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + high: Chartist.isNum(options.high) ? options.high : options.axisY.high, + low: Chartist.isNum(options.low) ? options.low : options.axisY.low + })); + } else { + axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + } - Chartist.createAxis( - axisY, - axisY.bounds.values, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); + axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); // Draw the series - this.data.series.forEach(function(series, seriesIndex) { - seriesGroups[seriesIndex] = this.svg.elem('g'); + data.raw.series.forEach(function(series, seriesIndex) { + var seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[seriesIndex].attr({ + seriesElement.attr({ 'series-name': series.name, 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[seriesIndex].addClass([ + seriesElement.addClass([ options.classNames.series, (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); @@ -2941,10 +3058,10 @@ var Chartist = { var pathCoordinates = [], pathData = []; - normalizedData[seriesIndex].forEach(function(value, valueIndex) { + data.normalized[seriesIndex].forEach(function(value, valueIndex) { var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[seriesIndex]) }; pathCoordinates.push(p.x, p.y); pathData.push({ @@ -2958,7 +3075,8 @@ var Chartist = { lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'), showPoint: Chartist.getSeriesOption(series, options, 'showPoint'), showLine: Chartist.getSeriesOption(series, options, 'showLine'), - showArea: Chartist.getSeriesOption(series, options, 'showArea') + showArea: Chartist.getSeriesOption(series, options, 'showArea'), + areaBase: Chartist.getSeriesOption(series, options, 'areaBase') }; var smoothing = typeof seriesOptions.lineSmooth === 'function' ? @@ -2973,13 +3091,13 @@ var Chartist = { if (seriesOptions.showPoint) { path.pathElements.forEach(function(pathElement) { - var point = seriesGroups[seriesIndex].elem('line', { + var point = seriesElement.elem('line', { x1: pathElement.x, y1: pathElement.y, x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': pathElement.data.value, + 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y, 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); @@ -2990,7 +3108,7 @@ var Chartist = { meta: pathElement.data.meta, series: series, seriesIndex: seriesIndex, - group: seriesGroups[seriesIndex], + group: seriesElement, element: point, x: pathElement.x, y: pathElement.y @@ -2999,32 +3117,31 @@ var Chartist = { } if(seriesOptions.showLine) { - var line = seriesGroups[seriesIndex].elem('path', { + var line = seriesElement.elem('path', { d: path.stringify() - }, options.classNames.line, true).attr({ - 'values': normalizedData[seriesIndex] - }, Chartist.xmlNs.uri); + }, options.classNames.line, true); this.eventEmitter.emit('draw', { type: 'line', - values: normalizedData[seriesIndex], + values: data.normalized[seriesIndex], path: path.clone(), chartRect: chartRect, index: seriesIndex, series: series, seriesIndex: seriesIndex, - group: seriesGroups[seriesIndex], + group: seriesElement, element: line }); } - if(seriesOptions.showArea) { + // Area currently only works with axes that support highLow! + if(seriesOptions.showArea && axisY.highLow) { // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(options.areaBase, axisY.bounds.max), axisY.bounds.min); + var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.highLow.high), axisY.highLow.low); // We project the areaBase value into screen coordinates - var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos; + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); // In order to form the area we'll first split the path by move commands so we can chunk it up into segments path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { @@ -3050,22 +3167,22 @@ var Chartist = { }).forEach(function createArea(areaPath) { // For each of our newly created area paths, we'll now create path elements by stringifying our path objects // and adding the created DOM elements to the correct series group - var area = seriesGroups[seriesIndex].elem('path', { + var area = seriesElement.elem('path', { d: areaPath.stringify() }, options.classNames.area, true).attr({ - 'values': normalizedData[seriesIndex] + 'values': data.normalized[seriesIndex] }, Chartist.xmlNs.uri); // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { type: 'area', - values: normalizedData[seriesIndex], + values: data.normalized[seriesIndex], path: areaPath.clone(), series: series, seriesIndex: seriesIndex, chartRect: chartRect, index: seriesIndex, - group: seriesGroups[seriesIndex], + group: seriesElement, element: area }); }.bind(this)); @@ -3287,11 +3404,13 @@ var Chartist = { * */ function createChart(options) { - var seriesGroups = []; - var data = Chartist.getDataArray(this.data, options.reverseData); - var normalizedData = options.distributeSeries ? data.map(function(value) { - return [value]; - }) : Chartist.normalizeDataArray(data, this.data.labels.length); + var data = { + raw: this.data, + normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) { + return [value]; + }) : Chartist.getDataArray(this.data, options.reverseData) + }; + var highLow; // Create new svg element @@ -3302,15 +3421,20 @@ var Chartist = { options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '') ); + // Drawing groups in correct order + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + if(options.stackBars) { // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = Chartist.serialMap(normalizedData, function serialSums() { + var serialSums = Chartist.serialMap(data.normalized, function serialSums() { return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); }); highLow = Chartist.getHighLow([serialSums], options); } else { - highLow = Chartist.getHighLow(normalizedData, options); + highLow = Chartist.getHighLow(data.normalized, options); } // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); @@ -3319,117 +3443,91 @@ var Chartist = { var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, - labelAxisStepCount, + labelAxisTicks, labelAxis, axisX, axisY; // We need to set step count based on some options combinations - if(options.distributeSeries && !options.stackBars) { - // If distributed series are enabled but stacked bars aren't, we need to use the one dimensional series array - // length as step count for the label axis - labelAxisStepCount = normalizedData.length; - } else if(options.distributeSeries && options.stackBars) { - // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore set step - // count to 1 - labelAxisStepCount = 1; + if(options.distributeSeries && options.stackBars) { + // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should + // use only the first label for the step axis + labelAxisTicks = data.raw.labels.slice(0, 1); } else { - // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length + // If distributed series are enabled but stacked bars aren't, we should use the series labels + // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array // as the bars are normalized - labelAxisStepCount = this.data.labels.length; + labelAxisTicks = data.raw.labels; } // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { - labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, { - stepCount: labelAxisStepCount + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { + ticks: labelAxisTicks }); - valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, { + valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, - scaleMinSpace: options.axisX.scaleMinSpace, - onlyInteger: options.axisX.onlyInteger, referenceValue: 0 - }); + })); } else { - labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, { - stepCount: labelAxisStepCount + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { + ticks: labelAxisTicks }); - valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, { + valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, - scaleMinSpace: options.axisY.scaleMinSpace, - onlyInteger: options.axisY.onlyInteger, referenceValue: 0 - }); + })); } - // Start drawing - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup), - gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup), - // Projected 0 point - zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos), - // Used to track the screen coordinates of stacked bars - stackedBarValues = []; + // Projected 0 point + var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0)); + // Used to track the screen coordinates of stacked bars + var stackedBarValues = []; - Chartist.createAxis( - labelAxis, - this.data.labels, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); - - Chartist.createAxis( - valueAxis, - valueAxis.bounds.values, - chartRect, - gridGroup, - labelGroup, - this.supportsForeignObject, - options, - this.eventEmitter - ); + labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); // Draw the series - this.data.series.forEach(function(series, seriesIndex) { + data.raw.series.forEach(function(series, seriesIndex) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = seriesIndex - (this.data.series.length - 1) / 2, + var biPol = seriesIndex - (data.raw.series.length - 1) / 2; // Half of the period width between vertical grid lines used to position bars - periodHalfLength; + var periodHalfLength; + // Current series SVG element + var seriesElement; // We need to set periodHalfLength based on some options combinations if(options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array // which is the series count and divide by 2 - periodHalfLength = labelAxis.axisLength / normalizedData.length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized.length / 2; } else if(options.distributeSeries && options.stackBars) { // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis // length by 2 periodHalfLength = labelAxis.axisLength / 2; } else { // On regular bar charts we should just use the series length - periodHalfLength = labelAxis.axisLength / normalizedData[seriesIndex].length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized[seriesIndex].length / 2; } - seriesGroups[seriesIndex] = this.svg.elem('g'); + // Adding the series group to the series element + seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written - seriesGroups[seriesIndex].attr({ + seriesElement.attr({ 'series-name': series.name, 'meta': Chartist.serialize(series.meta) }, Chartist.xmlNs.uri); // Use series class from series data or if not set generate one - seriesGroups[seriesIndex].addClass([ + seriesElement.addClass([ options.classNames.series, (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - normalizedData[seriesIndex].forEach(function(value, valueIndex) { + data.normalized[seriesIndex].forEach(function(value, valueIndex) { var projected, bar, previousStack, @@ -3452,13 +3550,13 @@ var Chartist = { // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos, - y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos + x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]) } } @@ -3483,7 +3581,7 @@ var Chartist = { positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; - bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({ + bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'value': value, 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); @@ -3496,7 +3594,7 @@ var Chartist = { series: series, seriesIndex: seriesIndex, chartRect: chartRect, - group: seriesGroups[seriesIndex], + group: seriesElement, element: bar }, positions)); }.bind(this)); diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 18e9e428..814a67cc 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.8.3 +/* Chartist.js 0.9.0 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.8.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bd;d++)a[c][d]=void 0;return a},c.getMetaData=function(a,b){var d=a.data?a.data[b]:a[b];return d?c.serialize(d.meta):void 0},c.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},c.projectLength=function(a,b,c){return b/c.range*a},c.getAvailableHeight=function(a,b){return Math.max((c.stripUnit(b.height)||a.height())-(b.chartPadding.top+b.chartPadding.bottom)-b.axisX.offset,0)},c.getHighLow=function(a,b){function c(a){if(a instanceof Array)for(var b=0;bd.high&&(d.high=a),f&&ak,m=f?c.rho(j.range):0;if(f&&c.projectLength(a,1,j)>=d)j.step=1;else if(f&&m=d)j.step=m;else for(;;)if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,f&&j.step%1!==0){j.step*=2;break}}for(h=j.min,i=j.max;h+j.step<=j.low;)h+=j.step;for(;i-j.step>=j.high;)i-=j.step;for(j.min=h,j.max=i,j.range=j.max-j.min,j.values=[],g=j.min;g<=j.max;g+=j.step)j.values.push(c.roundWithPrecision(g));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.pos,j[d.units.pos+"2"]=a.pos,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.createLabel=function(a,b,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a.pos+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=a.len,m[e.counterUnits.len]=f-10,j){var n=''+d[b]+"";l=h.foreignObject(n,c.extend({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[b]);k.emit("draw",c.extend({type:"label",axis:e,index:b,group:h,element:l,text:d[b]},m))},c.createAxis=function(a,b,d,e,f,g,h,i){var j=h["axis"+a.units.pos.toUpperCase()],k=b.map(a.projectValue.bind(a)),l=b.map(j.labelInterpolationFnc);k.forEach(function(b,k){var m={x:0,y:0};(l[k]||0===l[k])&&("x"===a.units.pos?(b.pos=d.x1+b.pos,m.x=h.axisX.labelOffset.x,"start"===h.axisX.position?m.y=d.padding.top+h.axisX.labelOffset.y+(g?5:20):m.y=d.y1+h.axisX.labelOffset.y+(g?5:20)):(b.pos=d.y1-b.pos,m.y=h.axisY.labelOffset.y-(g?b.len:0),"start"===h.axisY.position?m.x=g?d.padding.left+h.axisY.labelOffset.x:d.x1-10:m.x=d.x2+h.axisY.labelOffset.x+10),j.showGrid&&c.createGrid(b,k,a,a.gridOffset,d[a.counterUnits.len](),e,[h.classNames.grid,h.classNames[a.units.dir]],i),j.showLabel&&c.createLabel(b,k,l,a,j.offset,m,f,[h.classNames.label,h.classNames[a.units.dir],h.classNames[j.position]],g,i))})},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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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,q).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,q)}).forEach(function(h){var i=b[g].elem("path",{d:h.stringify()},a.classNames.area,!0).attr({values:d[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:d[g],path:h.clone(),series:f,seriesIndex:g,chartRect:e,index:g,group:b[g],element:i})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:i.bounds,chartRect:e,axisX:h,axisY:i,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,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,showLine:!0,showPoint:!0,showArea:!1,areaBase:0,lineSmooth:!0,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",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=[],e=c.getDataArray(this.data,a.reverseData),g=a.distributeSeries?e.map(function(a){return[a]}):c.normalizeDataArray(e,this.data.labels.length);if(this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:"")),a.stackBars){var h=c.serialMap(g,function(){return Array.prototype.slice.call(arguments).reduce(c.sum,0)});b=c.getHighLow([h],a)}else b=c.getHighLow(g,a);b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var i,j,k,l,m,n=c.createChartRect(this.svg,a,f.padding);j=a.distributeSeries&&!a.stackBars?g.length:a.distributeSeries&&a.stackBars?1:this.data.labels.length,a.horizontalBars?(k=m=new c.StepAxis(c.Axis.units.y,n,{stepCount:j}),i=l=new c.LinearScaleAxis(c.Axis.units.x,n,{highLow:b,scaleMinSpace:a.axisX.scaleMinSpace,onlyInteger:a.axisX.onlyInteger,referenceValue:0})):(k=l=new c.StepAxis(c.Axis.units.x,n,{stepCount:j}),i=m=new c.LinearScaleAxis(c.Axis.units.y,n,{highLow:b,scaleMinSpace:a.axisY.scaleMinSpace,onlyInteger:a.axisY.onlyInteger,referenceValue:0}));var o=this.svg.elem("g").addClass(a.classNames.labelGroup),p=this.svg.elem("g").addClass(a.classNames.gridGroup),q=a.horizontalBars?n.x1+i.projectValue(0).pos:n.y1-i.projectValue(0).pos,r=[];c.createAxis(k,this.data.labels,n,p,o,this.supportsForeignObject,a,this.eventEmitter),c.createAxis(i,i.bounds.values,n,p,o,this.supportsForeignObject,a,this.eventEmitter),this.data.series.forEach(function(b,e){var f,h=e-(this.data.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?k.axisLength/g.length/2:a.distributeSeries&&a.stackBars?k.axisLength/2:k.axisLength/g[e].length/2,d[e]=this.svg.elem("g"),d[e].attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),d[e].addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),g[e].forEach(function(j,l){var m,o,p,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:l,m=a.horizontalBars?{x:n.x1+i.projectValue(j||0,l,g[e]).pos,y:n.y1-k.projectValue(j||0,s,g[e]).pos}:{x:n.x1+k.projectValue(j||0,s,g[e]).pos,y:n.y1-i.projectValue(j||0,l,g[e]).pos},m[k.units.pos]+=f*(a.horizontalBars?-1:1),m[k.units.pos]+=a.stackBars||a.distributeSeries?0:h*a.seriesBarDistance*(a.horizontalBars?-1:1),p=r[l]||q,r[l]=p-(q-m[k.counterUnits.pos]),void 0!==j){var t={};t[k.units.pos+"1"]=m[k.units.pos],t[k.units.pos+"2"]=m[k.units.pos],t[k.counterUnits.pos+"1"]=a.stackBars?p:q,t[k.counterUnits.pos+"2"]=a.stackBars?r[l]:m[k.counterUnits.pos],o=d[e].elem("line",t,a.classNames.bar).attr({value:j,meta:c.getMetaData(b,l)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:j,index:l,meta:c.getMetaData(b,l),series:b,seriesIndex:e,chartRect:n,group:d[e],element:o},t))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:i.bounds,chartRect:n,axisX:l,axisY:m,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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({ -style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&cl,n=f?c.rho(k.range):0;if(f&&c.projectLength(a,1,k)>=d)k.step=1;else if(f&&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,f&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(h=k.min,i=k.max;h+k.step<=k.low;)h+=k.step;for(;i-k.step>=k.high;)i-=k.step;for(k.min=h,k.max=i,k.range=k.max-k.min,k.values=[],g=k.min;g<=k.max;g+=k.step)k.values.push(c.roundWithPrecision(g));return 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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData).map(function(a){return[a]}):c.getDataArray(this.data,a.reverseData)};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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).reduce(c.sum,0)});b=c.getHighLow([i],a)}else b=c.getHighLow(d.normalized,a);b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(l=n=new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}),j=m=new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0}))):(l=m=new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}),j=n=new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g||0,k,d.normalized[e]),y:o.y1-l.projectValue(g||0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g||0,s,d.normalized[e]),y:o.y1-j.projectValue(g||0,k,d.normalized[e])},m[l.units.pos]+=f*(a.horizontalBars?-1:1),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],n=h.elem("line",t,a.classNames.bar).attr({value:g,meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 6d249bd1..c3cc280c 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","recursiveConvert","isNaN","hasOwnProperty","reversed","normalizePadding","padding","fallback","top","right","bottom","left","normalizeDataArray","dataArray","j","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","recursiveHighLow","findHigh","highLow","high","findLow","low","Number","MAX_VALUE","rho","gcd","p","q","f","x","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","values","push","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","y","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","projectedValue","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","createAxis","gridGroup","labelGroup","axisOptions","toUpperCase","projectedValues","projectValue","bind","labelValues","labelInterpolationFnc","showGrid","gridOffset","classNames","grid","dir","showLabel","label","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","setTimeout","Error","attributes","parent","insertFirst","Element","createElementNS","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","splitByCommand","joinedPath","m","l","a","Axis","axisUnits","rectEnd","rectStart","rectOffset","LinearScaleAxis","axisUnit","StepAxis","stepLength","stepCount","stretch","seriesGroups","normalizedData","chart","fullWidth","seriesIndex","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","smoothing","point","areaBase","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisStepCount","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.8.3\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.8.3'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function (data, reverse) {\n // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\n // Rcursively 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(value === undefined || value === null || (typeof value === 'number' && isNaN(value))) {\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n return +value;\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 /**\n * Adds missing values at the end of the array. This array contains the data, that will be visualized in the chart\n *\n * @memberof Chartist.Core\n * @param {Array} dataArray The array that contains the data to be visualized in the chart. The array in this parameter will be modified by function.\n * @param {Number} length The length of the x-axis data array.\n * @return {Array} The array that got updated with missing values.\n */\n Chartist.normalizeDataArray = function (dataArray, length) {\n for (var i = 0; i < dataArray.length; i++) {\n if (dataArray[i].length === length) {\n continue;\n }\n\n for (var j = dataArray[i].length; j < length; j++) {\n dataArray[i][j] = undefined;\n }\n }\n\n return dataArray;\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? Chartist.serialize(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.stripUnit(options.height) || 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} dataArray The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (dataArray, options) {\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 findHigh = options.high === undefined,\n 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 instanceof Array) {\n for (var i = 0; i < data.length; i++) {\n recursiveHighLow(data[i]);\n }\n } else {\n if (findHigh && data > highLow.high) {\n highLow.high = data;\n }\n\n if (findLow && data < highLow.low) {\n highLow.low = data;\n }\n }\n }\n\n // Start to find highest and lowest number recursively\n recursiveHighLow(dataArray);\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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 }\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 projectedValue\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(projectedValue, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = projectedValue.pos;\n positionalData[axis.units.pos + '2'] = projectedValue.pos;\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 label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param projectedValue\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(projectedValue, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = projectedValue.pos + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = projectedValue.len;\n positionalData[axis.counterUnits.len] = 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 * This function creates a whole axis with its grid lines and labels based on an axis model and a chartRect.\n *\n * @memberof Chartist.Core\n * @param axis\n * @param data\n * @param chartRect\n * @param gridGroup\n * @param labelGroup\n * @param useForeignObject\n * @param options\n * @param eventEmitter\n */\n Chartist.createAxis = function(axis, data, chartRect, gridGroup, labelGroup, useForeignObject, options, eventEmitter) {\n var axisOptions = options['axis' + axis.units.pos.toUpperCase()];\n var projectedValues = data.map(axis.projectValue.bind(axis));\n var labelValues = data.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(!labelValues[index] && labelValues[index] !== 0) {\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(axis.units.pos === 'x') {\n projectedValue.pos = chartRect.x1 + projectedValue.pos;\n labelOffset.x = options.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(options.axisX.position === 'start') {\n labelOffset.y = chartRect.padding.top + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = chartRect.y1 + options.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue.pos = chartRect.y1 - projectedValue.pos;\n labelOffset.y = options.axisY.labelOffset.y - (useForeignObject ? projectedValue.len : 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(options.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? chartRect.padding.left + options.axisY.labelOffset.x : chartRect.x1 - 10;\n } else {\n labelOffset.x = chartRect.x2 + options.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, axis, axis.gridOffset, chartRect[axis.counterUnits.len](), gridGroup, [\n options.classNames.grid,\n options.classNames[axis.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, index, labelValues, axis, axisOptions.offset, labelOffset, labelGroup, [\n options.classNames.label,\n options.classNames[axis.units.dir],\n options.classNames[axisOptions.position]\n ], useForeignObject, eventEmitter);\n }\n });\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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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;/**\n * Axis base class used to implement different axis types\n *\n * @module Chartist.Axis\n */\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, 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.options = options;\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\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 linear scale axis uses standard linear scale projection of values along an axis.\n *\n * @module Chartist.LinearScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function LinearScaleAxis(axisUnit, chartRect, options) {\n Chartist.LinearScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.bounds = Chartist.getBounds(this.axisLength, options.highLow, options.scaleMinSpace, options.referenceValue, options.onlyInteger);\n }\n\n function projectValue(value) {\n return {\n pos: this.axisLength * (value - this.bounds.min) / this.bounds.range,\n len: Chartist.projectLength(this.axisLength, this.bounds.step, this.bounds)\n };\n }\n\n Chartist.LinearScaleAxis = Chartist.Axis.extend({\n constructor: LinearScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * Step axis for step based charts like bar chart or step based line chart\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options);\n\n this.stepLength = this.axisLength / (options.stepCount - (options.stretch ? 1 : 0));\n }\n\n function projectValue(value, index) {\n return {\n pos: this.stepLength * index,\n len: this.stepLength\n };\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 // 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 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 // 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 // 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 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 seriesGroups = [];\n var normalizedData = Chartist.normalizeDataArray(Chartist.getDataArray(this.data, options.reverseData), this.data.labels.length);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var highLow = Chartist.getHighLow(normalizedData, options);\n\n var axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: this.data.labels.length,\n stretch: options.fullWidth\n });\n\n var axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger\n });\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n\n Chartist.createAxis(\n axisX,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n axisY,\n axisY.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.series.forEach(function(series, seriesIndex) {\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n normalizedData[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, normalizedData[seriesIndex]).pos\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 };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : 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 = seriesGroups[seriesIndex].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 'value': pathElement.data.value,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 group: seriesGroups[seriesIndex],\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesGroups[seriesIndex].elem('path', {\n d: path.stringify()\n }, options.classNames.line, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: normalizedData[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesGroups[seriesIndex],\n element: line\n });\n }\n\n if(seriesOptions.showArea) {\n // If areaBase is outside the chart area (< low or > high) 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(options.areaBase, axisY.bounds.max), axisY.bounds.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase).pos;\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 = seriesGroups[seriesIndex].elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true).attr({\n 'values': normalizedData[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: normalizedData[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesGroups[seriesIndex],\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 seriesGroups = [];\n var data = Chartist.getDataArray(this.data, options.reverseData);\n var normalizedData = options.distributeSeries ? data.map(function(value) {\n return [value];\n }) : Chartist.normalizeDataArray(data, this.data.labels.length);\n var highLow;\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 if(options.stackBars) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(normalizedData, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(normalizedData, options);\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 labelAxisStepCount,\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 but stacked bars aren't, we need to use the one dimensional series array\n // length as step count for the label axis\n labelAxisStepCount = normalizedData.length;\n } else 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 set step\n // count to 1\n labelAxisStepCount = 1;\n } else {\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array length\n // as the bars are normalized\n labelAxisStepCount = this.data.labels.length;\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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisX = new Chartist.LinearScaleAxis(Chartist.Axis.units.x, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisX.scaleMinSpace,\n onlyInteger: options.axisX.onlyInteger,\n referenceValue: 0\n });\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, chartRect, {\n stepCount: labelAxisStepCount\n });\n\n valueAxis = axisY = new Chartist.LinearScaleAxis(Chartist.Axis.units.y, chartRect, {\n highLow: highLow,\n scaleMinSpace: options.axisY.scaleMinSpace,\n onlyInteger: options.axisY.onlyInteger,\n referenceValue: 0\n });\n }\n\n // Start drawing\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup),\n gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup),\n // Projected 0 point\n zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0).pos) : (chartRect.y1 - valueAxis.projectValue(0).pos),\n // Used to track the screen coordinates of stacked bars\n stackedBarValues = [];\n\n Chartist.createAxis(\n labelAxis,\n this.data.labels,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n Chartist.createAxis(\n valueAxis,\n valueAxis.bounds.values,\n chartRect,\n gridGroup,\n labelGroup,\n this.supportsForeignObject,\n options,\n this.eventEmitter\n );\n\n // Draw the series\n this.data.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 - (this.data.series.length - 1) / 2,\n // Half of the period width between vertical grid lines used to position bars\n periodHalfLength;\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 / normalizedData.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 / normalizedData[seriesIndex].length / 2;\n }\n\n seriesGroups[seriesIndex] = this.svg.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesGroups[seriesIndex].attr({\n 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[seriesIndex].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n normalizedData[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 || 0, valueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, normalizedData[seriesIndex]).pos,\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, normalizedData[seriesIndex]).pos\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesGroups[seriesIndex].elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\n chartRect: chartRect,\n group: seriesGroups[seriesIndex],\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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","x","getNumberOrUndefined","y","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","optimizationCounter","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.0'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n if(multi) {\n return {\n x: Chartist.getNumberOrUndefined(value.x),\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 y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value)\n };\n } else {\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 ? Chartist.serialize(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.stripUnit(options.height) || 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 all the optional values for the chart\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 findHigh = options.high === undefined,\n 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 // 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension] || 0;\n } else {\n return 0;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n optimizationCounter = 0,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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 this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos);\n this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger);\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 this.highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos);\n this.divisor = options.divisor || 1;\n this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) {\n return this.highLow.low + (this.highLow.high - this.highLow.low) / this.divisor * index;\n }.bind(this));\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.highLow.low) / (this.highLow.high - this.highLow.low);\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 while 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesElement,\n element: line\n });\n }\n\n // Area currently only works with axes that support highLow!\n if(seriesOptions.showArea && axisY.highLow) {\n // If areaBase is outside the chart area (< low or > high) 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.highLow.high), axisY.highLow.low);\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData)\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(data.normalized, options);\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.raw.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.raw.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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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 || 0, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex])\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/package.json b/package.json index 0a327544..740b2dd4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.8.3", + "version": "0.9.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From cfeb6df4d37421699518bc02c3c82e113133639d Mon Sep 17 00:00:00 2001 From: Kevin Kirsche Date: Wed, 10 Jun 2015 18:50:58 -0400 Subject: [PATCH 280/593] Remove moot `version` property from bower.json Per bower/bower.json-spec@a325da3 --- bower.json | 1 - 1 file changed, 1 deletion(-) diff --git a/bower.json b/bower.json index 6fe297cf..73b3c0f4 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,5 @@ { "name": "chartist", - "version": "0.9.0", "main": [ "./dist/chartist.min.js", "./dist/chartist.min.css" From fb8427ecc855e0ac4625d9281376b34b6e39b5e1 Mon Sep 17 00:00:00 2001 From: Ankit Sardesai Date: Thu, 11 Jun 2015 16:59:55 -0700 Subject: [PATCH 281/593] Updated width and height to take into account the inverting that happens with options.horizontalBar --- src/scripts/core.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 9fab8d1a..c8c73b4b 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -718,8 +718,8 @@ var Chartist = { var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust - width = Math.max(width, xAxisOffset + normalizedPadding.left + normalizedPadding.right); - height = Math.max(height, yAxisOffset + normalizedPadding.top + normalizedPadding.bottom); + width = Math.max(width, (options.horizontalBar ? yAxisOffset : xAxisOffset) + normalizedPadding.left + normalizedPadding.right); + height = Math.max(height, (options.horizontalBar ? xAxisOffset : yAxisOffset) + normalizedPadding.top + normalizedPadding.bottom); var chartRect = { padding: normalizedPadding, From a04b8cd6862c48876709e5edfc5241bf15f4beea Mon Sep 17 00:00:00 2001 From: Alex Batalov Date: Tue, 16 Jun 2015 16:01:10 +0500 Subject: [PATCH 282/593] Fixed SVG duplication for old browsers --- src/scripts/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 9fab8d1a..45d62596 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -287,7 +287,7 @@ var Chartist = { // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttribute(Chartist.xmlNs.qualifiedName); + return svg.getAttributeNS('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix); }).forEach(function removePreviousElement(svg) { container.removeChild(svg); }); From aa539df700e77ba672eeb19ddde42fd9a148a7ad Mon Sep 17 00:00:00 2001 From: Ankit Sardesai Date: Tue, 16 Jun 2015 11:59:57 -0700 Subject: [PATCH 283/593] Changed height/width calculation to use x/y axis always --- src/scripts/core.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index c8c73b4b..7e3ab11a 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -718,8 +718,8 @@ var Chartist = { var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust - width = Math.max(width, (options.horizontalBar ? yAxisOffset : xAxisOffset) + normalizedPadding.left + normalizedPadding.right); - height = Math.max(height, (options.horizontalBar ? xAxisOffset : yAxisOffset) + normalizedPadding.top + normalizedPadding.bottom); + width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right); + height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom); var chartRect = { padding: normalizedPadding, From 37c9daaddc089d3f98874624ab979750f2cade51 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 24 Jun 2015 14:28:12 +0200 Subject: [PATCH 284/593] doc: Fixed point label plugin dependency --- bower.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 73b3c0f4..419e22d1 100644 --- a/bower.json +++ b/bower.json @@ -11,7 +11,7 @@ "compass-mixins": "~1.0.2", "codemirror": "~4.12.0", "base64": "~0.3.0", - "chartist-plugin-pointlabels": "~0.0.3", + "chartist-plugin-pointlabels": "~0.0.4", "chartist-plugin-sketchy": "~0.0.2", "chartist-plugin-accessibility": "~0.0.2", "chartist-plugin-tooltip": "~0.0.8", @@ -29,6 +29,6 @@ "test" ], "resolutions": { - "chartist": "~0.8.0" + "chartist": "~0.9.0" } } From 9106a1aaa50b58e514299d31588520c2a4ce430a Mon Sep 17 00:00:00 2001 From: alexstanbury Date: Wed, 24 Jun 2015 18:25:13 +0100 Subject: [PATCH 285/593] Added axis title plugin to plugins page. --- site/data/pages/plugins.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index b22996c2..0485dd44 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -179,6 +179,24 @@ sections: - - 'Link:' - 'chartist-plugin-sketchy' + - type: sub-section + data: + title: Axis Title Plugin + level: 4 + items: + - type: text + data: + text: > + The axis title plugin allows you to add simple titles to your axises. + - type: table + data: + rows: + - + - 'Author:' + - Alex Stanbury + - + - 'Link:' + - 'chartist-plugin-axistitle' - title: Develop a plugin level: 3 items: From 851d696b314ccb0a26498fc690a1206e1dde32e6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 24 Jun 2015 20:39:11 +0200 Subject: [PATCH 286/593] Axis expose a range object that represents actual min / max values on charts, fixes #364 --- src/scripts/axes/auto-scale-axis.js | 8 ++++++-- src/scripts/axes/fixed-scale-axis.js | 10 +++++++--- src/scripts/charts/line.js | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js index ebc402aa..430c598a 100644 --- a/src/scripts/axes/auto-scale-axis.js +++ b/src/scripts/axes/auto-scale-axis.js @@ -25,8 +25,12 @@ function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options - this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); - this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + this.range = { + min: this.bounds.min, + max: this.bounds.max + }; Chartist.AutoScaleAxis.super.constructor.call(this, axisUnit, diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index e2311564..8434713a 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -22,11 +22,15 @@ 'use strict'; function FixedScaleAxis(axisUnit, data, chartRect, options) { - this.highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { - return this.highLow.low + (this.highLow.high - this.highLow.low) / this.divisor * index; + return highLow.low + (highLow.high - highLow.low) / this.divisor * index; }.bind(this)); + this.range = { + min: highLow.low, + max: highLow.high + }; Chartist.FixedScaleAxis.super.constructor.call(this, axisUnit, @@ -38,7 +42,7 @@ } function projectValue(value) { - return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.highLow.low) / (this.highLow.high - this.highLow.low); + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); } Chartist.FixedScaleAxis = Chartist.Axis.extend({ diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 16d15cff..bccdbf74 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -242,11 +242,11 @@ }); } - // Area currently only works with axes that support highLow! - if(seriesOptions.showArea && axisY.highLow) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // Area currently only works with axes that support a range! + if(seriesOptions.showArea && axisY.range) { + // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.highLow.high), axisY.highLow.low); + var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); From 9d8c258fbfff8ba2450d73897455cff5151d5ad6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 24 Jun 2015 20:53:06 +0200 Subject: [PATCH 287/593] Distribution and version bump to 0.9.1 --- CHANGELOG.md | 6 ++++++ dist/chartist.js | 36 ++++++++++++++++++++++-------------- dist/chartist.min.js | 6 +++--- dist/chartist.min.js.map | 2 +- package.json | 2 +- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8ff34d3..577f9777 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v0.9.1 - 24 Jun 2015 +-------------------- +- Fixed bug with areaBase narrowing process in area charts, fixes #364 +- Fixed bug on bar chart where wrong offset was used (axis offset), fixes #347 (Thanks to @amsardesai !) +- Fixed bug with namespace attributes that caused duplication of SVG element on updates in old browsers (Thanks to @radist2s !) + v0.9.0 - 10 Jun 2015 -------------------- - Major refactoring of axis and projection code, added possibility to configure axes when creating a chart diff --git a/dist/chartist.js b/dist/chartist.js index d6668769..4df27a0b 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.0 +/* Chartist.js 0.9.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.0' + version: '0.9.1' }; (function (window, document, Chartist) { @@ -308,7 +308,7 @@ var Chartist = { // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttribute(Chartist.xmlNs.qualifiedName); + return svg.getAttributeNS('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix); }).forEach(function removePreviousElement(svg) { container.removeChild(svg); }); @@ -739,8 +739,8 @@ var Chartist = { var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust - width = Math.max(width, xAxisOffset + normalizedPadding.left + normalizedPadding.right); - height = Math.max(height, yAxisOffset + normalizedPadding.top + normalizedPadding.bottom); + width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right); + height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom); var chartRect = { padding: normalizedPadding, @@ -2782,8 +2782,12 @@ var Chartist = { function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options - this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); - this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + this.range = { + min: this.bounds.min, + max: this.bounds.max + }; Chartist.AutoScaleAxis.super.constructor.call(this, axisUnit, @@ -2826,11 +2830,15 @@ var Chartist = { 'use strict'; function FixedScaleAxis(axisUnit, data, chartRect, options) { - this.highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { - return this.highLow.low + (this.highLow.high - this.highLow.low) / this.divisor * index; + return highLow.low + (highLow.high - highLow.low) / this.divisor * index; }.bind(this)); + this.range = { + min: highLow.low, + max: highLow.high + }; Chartist.FixedScaleAxis.super.constructor.call(this, axisUnit, @@ -2842,7 +2850,7 @@ var Chartist = { } function projectValue(value) { - return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.highLow.low) / (this.highLow.high - this.highLow.low); + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); } Chartist.FixedScaleAxis = Chartist.Axis.extend({ @@ -3134,11 +3142,11 @@ var Chartist = { }); } - // Area currently only works with axes that support highLow! - if(seriesOptions.showArea && axisY.highLow) { - // If areaBase is outside the chart area (< low or > high) we need to set it respectively so that + // Area currently only works with axes that support a range! + if(seriesOptions.showArea && axisY.range) { + // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.highLow.high), axisY.highLow.low); + var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 814a67cc..57e8d488 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.9.0 +/* Chartist.js 0.9.1 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.0"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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.getAttribute(c.xmlNs.qualifiedName)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&cl,n=f?c.rho(k.range):0;if(f&&c.projectLength(a,1,k)>=d)k.step=1;else if(f&&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,f&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(h=k.min,i=k.max;h+k.step<=k.low;)h+=k.step;for(;i-k.step>=k.high;)i-=k.step;for(k.min=h,k.max=i,k.range=k.max-k.min,k.values=[],g=k.min;g<=k.max;g+=k.step)k.values.push(c.roundWithPrecision(g));return 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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,g+j.left+j.right),i=Math.max(i,f+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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData).map(function(a){return[a]}):c.getDataArray(this.data,a.reverseData)};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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).reduce(c.sum,0)});b=c.getHighLow([i],a)}else b=c.getHighLow(d.normalized,a);b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(l=n=new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}),j=m=new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0}))):(l=m=new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}),j=n=new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g||0,k,d.normalized[e]),y:o.y1-l.projectValue(g||0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g||0,s,d.normalized[e]),y:o.y1-j.projectValue(g||0,k,d.normalized[e])},m[l.units.pos]+=f*(a.horizontalBars?-1:1),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],n=h.elem("line",t,a.classNames.bar).attr({value:g,meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&cl,n=f?c.rho(k.range):0;if(f&&c.projectLength(a,1,k)>=d)k.step=1;else if(f&&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,f&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(h=k.min,i=k.max;h+k.step<=k.low;)h+=k.step;for(;i-k.step>=k.high;)i-=k.step;for(k.min=h,k.max=i,k.range=k.max-k.min,k.values=[],g=k.min;g<=k.max;g+=k.step)k.values.push(c.roundWithPrecision(g));return 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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData).map(function(a){return[a]}):c.getDataArray(this.data,a.reverseData)};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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).reduce(c.sum,0)});b=c.getHighLow([i],a)}else b=c.getHighLow(d.normalized,a);b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(l=n=new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}),j=m=new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0}))):(l=m=new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}),j=n=new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g||0,k,d.normalized[e]),y:o.y1-l.projectValue(g||0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g||0,s,d.normalized[e]),y:o.y1-j.projectValue(g||0,k,d.normalized[e])},m[l.units.pos]+=f*(a.horizontalBars?-1:1),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],n=h.elem("line",t,a.classNames.bar).attr({value:g,meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index c3cc280c..1f9b081c 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttribute","xmlNs","qualifiedName","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","x","getNumberOrUndefined","y","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","optimizationCounter","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","uri","firstChild","insertBefore","ns","getAttributeNS","prefix","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.0\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.0'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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.getAttribute(Chartist.xmlNs.qualifiedName);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n if(multi) {\n return {\n x: Chartist.getNumberOrUndefined(value.x),\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 y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value)\n };\n } else {\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 ? Chartist.serialize(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.stripUnit(options.height) || 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 all the optional values for the chart\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 findHigh = options.high === undefined,\n 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 // 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension] || 0;\n } else {\n return 0;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n optimizationCounter = 0,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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, xAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, yAxisOffset + 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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 this.highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos);\n this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], this.highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger);\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 this.highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos);\n this.divisor = options.divisor || 1;\n this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) {\n return this.highLow.low + (this.highLow.high - this.highLow.low) / this.divisor * index;\n }.bind(this));\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.highLow.low) / (this.highLow.high - this.highLow.low);\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 while 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n group: seriesElement,\n element: line\n });\n }\n\n // Area currently only works with axes that support highLow!\n if(seriesOptions.showArea && axisY.highLow) {\n // If areaBase is outside the chart area (< low or > high) 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.highLow.high), axisY.highLow.low);\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData)\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(data.normalized, options);\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.raw.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.raw.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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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 || 0, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex])\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","x","getNumberOrUndefined","y","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","optimizationCounter","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.1\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.1'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n if(multi) {\n return {\n x: Chartist.getNumberOrUndefined(value.x),\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 y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value)\n };\n } else {\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 ? Chartist.serialize(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.stripUnit(options.height) || 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 all the optional values for the chart\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 findHigh = options.high === undefined,\n 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 // 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension] || 0;\n } else {\n return 0;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n optimizationCounter = 0,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, options, axisUnit.pos);\n this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.referenceValue, 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 = Chartist.getHighLow(data.normalized, 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.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 while 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData)\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(data.normalized, options);\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.raw.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.raw.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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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 || 0, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex])\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/package.json b/package.json index 740b2dd4..adbff413 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.0", + "version": "0.9.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 6111eda9e2dff2d3f977c7cb3f38f041a07da0b7 Mon Sep 17 00:00:00 2001 From: Anthony Jimenez Date: Wed, 24 Jun 2015 16:11:08 -0700 Subject: [PATCH 288/593] Added a label group for Pie charts to prevent occlusion by slices. --- src/scripts/charts/pie.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index f33295e9..25ceae7b 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -79,6 +79,7 @@ */ function createChart(options) { var seriesGroups = [], + labelsGroup, chartRect, radius, labelRadius, @@ -128,6 +129,11 @@ return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; + //if we need to show labels we create the label group now + if(options.showLabel) { + labelsGroup = this.svg.elem('g', null, null, true); + } + // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { @@ -208,7 +214,7 @@ interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); if(interpolatedValue || interpolatedValue === 0) { - var labelElement = seriesGroups[i].elem('text', { + var labelElement = labelsGroup.elem('text', { dx: labelPosition.x, dy: labelPosition.y, 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) @@ -218,7 +224,7 @@ this.eventEmitter.emit('draw', { type: 'label', index: i, - group: seriesGroups[i], + group: labelsGroup, element: labelElement, text: '' + interpolatedValue, x: labelPosition.x, From 87916c763a979098a2d8d5785592408f5992a623 Mon Sep 17 00:00:00 2001 From: alexstanbury Date: Thu, 25 Jun 2015 10:08:21 +0100 Subject: [PATCH 289/593] Updated example and bower config. --- site/examples/example-plugin-axistitle.js | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 site/examples/example-plugin-axistitle.js diff --git a/site/examples/example-plugin-axistitle.js b/site/examples/example-plugin-axistitle.js new file mode 100644 index 00000000..620d1fe5 --- /dev/null +++ b/site/examples/example-plugin-axistitle.js @@ -0,0 +1,36 @@ +new Chartist.Line('.ct-chart', { + labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + series: [ + {name: 'Income', data: [20000, 30000, 35000, 32000, 40000, 42000, 50000, 62000, 80000, 94000, 100000, 120000]}, + {name: 'Expenses', data: [10000, 15000, 12000, 14000, 20000, 23000, 22000, 24000, 21000, 18000, 30000, 32000]} + ] +}, { + fullWidth: true, + lineSmooth: false, + chartPadding: { + right: 20, + left: 10 + }, + axisX: { + labelInterpolationFnc: function(value) { + return value.split('').slice(0, 3).join(''); + } + }, + plugins: [ + Chartist.plugins.ctAccessibility({ + caption: 'Fiscal year 2015', + seriesHeader: 'business numbers', + summary: 'A graphic that shows the business numbers of the fiscal year 2015', + valueTransform: function(value) { + return value + ' dollar'; + }, + // ONLY USE THIS IF YOU WANT TO MAKE YOUR ACCESSIBILITY TABLE ALSO VISIBLE! + visuallyHiddenStyles: 'position: absolute; top: 100%; width: 100%; font-size: 11px; overflow-x: auto; background-color: rgba(0, 0, 0, 0.1); padding: 10px' + }) + ] +}); + +// This is only used for the example on the Chartist example page +$chart.parent().css({ + 'margin-bottom': '160px' +}); From 968dd8f06ead776ca7fcd5aa744fb411f25022ad Mon Sep 17 00:00:00 2001 From: alexstanbury Date: Thu, 25 Jun 2015 10:09:26 +0100 Subject: [PATCH 290/593] Updated example and bower config. --- bower.json | 1 + site/data/pages/plugins.yml | 8 ++- site/examples/example-plugin-axistitle.js | 68 +++++++++++------------ site/layouts/default.hbs | 1 + 4 files changed, 43 insertions(+), 35 deletions(-) diff --git a/bower.json b/bower.json index 419e22d1..ef695161 100644 --- a/bower.json +++ b/bower.json @@ -15,6 +15,7 @@ "chartist-plugin-sketchy": "~0.0.2", "chartist-plugin-accessibility": "~0.0.2", "chartist-plugin-tooltip": "~0.0.8", + "chartist-plugin-axistitle": "~0.0.1", "matchMedia": "~0.2.0" }, "ignore": [ diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 0485dd44..2a699c2e 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -187,7 +187,13 @@ sections: - type: text data: text: > - The axis title plugin allows you to add simple titles to your axises. + The axis title plugin allows you to add simple titles to your axes. + - type: live-example + data: + id: example-plugin-axistitle + classes: ct-golden-section + intro: > + Create beautiful hand drawn charts using the Chartist Sketchy plugin. - type: table data: rows: diff --git a/site/examples/example-plugin-axistitle.js b/site/examples/example-plugin-axistitle.js index 620d1fe5..04e94bc5 100644 --- a/site/examples/example-plugin-axistitle.js +++ b/site/examples/example-plugin-axistitle.js @@ -1,36 +1,36 @@ new Chartist.Line('.ct-chart', { - labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - series: [ - {name: 'Income', data: [20000, 30000, 35000, 32000, 40000, 42000, 50000, 62000, 80000, 94000, 100000, 120000]}, - {name: 'Expenses', data: [10000, 15000, 12000, 14000, 20000, 23000, 22000, 24000, 21000, 18000, 30000, 32000]} - ] + labels: ['0-15', '16-30', '31-45', '46-60', '61-75', '76-90', '91-105', '106-120'], + series: [1, 3, 7, 12, 1, 2, 1, 0] }, { - fullWidth: true, - lineSmooth: false, - chartPadding: { - right: 20, - left: 10 - }, - axisX: { - labelInterpolationFnc: function(value) { - return value.split('').slice(0, 3).join(''); - } - }, - plugins: [ - Chartist.plugins.ctAccessibility({ - caption: 'Fiscal year 2015', - seriesHeader: 'business numbers', - summary: 'A graphic that shows the business numbers of the fiscal year 2015', - valueTransform: function(value) { - return value + ' dollar'; - }, - // ONLY USE THIS IF YOU WANT TO MAKE YOUR ACCESSIBILITY TABLE ALSO VISIBLE! - visuallyHiddenStyles: 'position: absolute; top: 100%; width: 100%; font-size: 11px; overflow-x: auto; background-color: rgba(0, 0, 0, 0.1); padding: 10px' - }) - ] -}); - -// This is only used for the example on the Chartist example page -$chart.parent().css({ - 'margin-bottom': '160px' -}); + chartPadding: { + top: 20, + right: 0, + bottom: 20, + left: 0 + }, + axisY: { + onlyInteger: true + }, + plugins: [ + Chartist.plugins.ctAxisTitle({ + axisX: { + axisTitle: 'Time (mins)', + axisClass: 'ct-axis-title', + offset: { + x: 0, + y: 50 + }, + textAnchor: 'middle' + }, + axisY: { + axisTitle: 'Goals', + axisClass: 'ct-axis-title', + offset: { + x: 0, + y: 0 + }, + flipTitle: false + } + }) + ] +}); \ No newline at end of file diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 2bf421dd..f36d516b 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -73,6 +73,7 @@ + From 7c48db0428bf205dbc263127ab385a4ba93c3122 Mon Sep 17 00:00:00 2001 From: alexstanbury Date: Thu, 25 Jun 2015 10:37:20 +0100 Subject: [PATCH 291/593] Added newline to example file. --- site/examples/example-plugin-axistitle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/examples/example-plugin-axistitle.js b/site/examples/example-plugin-axistitle.js index 04e94bc5..ff974dcf 100644 --- a/site/examples/example-plugin-axistitle.js +++ b/site/examples/example-plugin-axistitle.js @@ -33,4 +33,4 @@ new Chartist.Line('.ct-chart', { } }) ] -}); \ No newline at end of file +}); From 976eb826570f719d8027d1353d8e68e28c267d83 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 27 Jun 2015 02:39:21 +0200 Subject: [PATCH 292/593] Enabled bar charts to use dynamic axes fixes #363, fixes #355 --- .../example-bar-with-circle-modify-drawing.js | 2 +- site/examples/example-dynamic-colours.js | 2 +- src/scripts/axes/auto-scale-axis.js | 2 +- src/scripts/axes/fixed-scale-axis.js | 2 +- src/scripts/charts/bar.js | 104 +++++++++++++----- src/scripts/core.js | 51 +++++---- 6 files changed, 110 insertions(+), 53 deletions(-) diff --git a/site/examples/example-bar-with-circle-modify-drawing.js b/site/examples/example-bar-with-circle-modify-drawing.js index a4617451..1b641cb8 100644 --- a/site/examples/example-bar-with-circle-modify-drawing.js +++ b/site/examples/example-bar-with-circle-modify-drawing.js @@ -22,7 +22,7 @@ chart.on('draw', function(data) { data.group.append(new Chartist.Svg('circle', { cx: data.x2, cy: data.y2, - r: Math.abs(data.value) * 2 + 5 + r: Math.abs(Chartist.getMultiValue(data.value)) * 2 + 5 }, 'ct-slice-pie')); } }); diff --git a/site/examples/example-dynamic-colours.js b/site/examples/example-dynamic-colours.js index 24230627..c14bc944 100644 --- a/site/examples/example-dynamic-colours.js +++ b/site/examples/example-dynamic-colours.js @@ -23,7 +23,7 @@ chart.on('draw', function(context) { // With the Chartist.Svg API we can easily set an attribute on our bar that just got drawn context.element.attr({ // Now we set the style attribute on our bar to override the default color of the bar. By using a HSL colour we can easily set the hue of the colour dynamically while keeping the same saturation and lightness. From the context we can also get the current value of the bar. We use that value to calculate a hue between 0 and 100 degree. This will make our bars appear green when close to the maximum and red when close to zero. - style: 'stroke: hsl(' + Math.floor(context.value / max * 100) + ', 50%, 50%);' + style: 'stroke: hsl(' + Math.floor(Chartist.getMultiValue(context.value) / max * 100) + ', 50%, 50%);' }); } }); diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js index 430c598a..ebecb619 100644 --- a/src/scripts/axes/auto-scale-axis.js +++ b/src/scripts/axes/auto-scale-axis.js @@ -26,7 +26,7 @@ function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); - this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); this.range = { min: this.bounds.min, max: this.bounds.max diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index 8434713a..b56112f9 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -22,7 +22,7 @@ 'use strict'; function FixedScaleAxis(axisUnit, data, chartRect, options) { - var highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return highLow.low + (highLow.high - highLow.low) / this.divisor * index; diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 963e7da8..1bae0dee 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -108,9 +108,9 @@ function createChart(options) { var data = { raw: this.data, - normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) { + normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { return [value]; - }) : Chartist.getDataArray(this.data, options.reverseData) + }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y') }; var highLow; @@ -131,12 +131,23 @@ if(options.stackBars) { // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized, function serialSums() { - return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); + return Array.prototype.slice.call(arguments).map(function(value) { + return value; + }).reduce(function(prev, curr) { + return { + x: prev.x + curr.x || 0, + y: prev.y + curr.y || 0 + }; + }, {x: 0, y: 0}); }); - highLow = Chartist.getHighLow([serialSums], options); + highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, { + referenceValue: 0 + }), options.horizontalBars ? 'x' : 'y'); } else { - highLow = Chartist.getHighLow(data.normalized, options); + highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, { + referenceValue: 0 + }), options.horizontalBars ? 'x' : 'y'); } // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); @@ -164,23 +175,45 @@ // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { - labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { - ticks: labelAxisTicks - }); + if(options.axisX.type === undefined) { + valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } - valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { - highLow: highLow, - referenceValue: 0 - })); + if(options.axisY.type === undefined) { + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + } } else { - labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { - ticks: labelAxisTicks - }); + if(options.axisX.type === undefined) { + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + } - valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { - highLow: highLow, - referenceValue: 0 - })); + if(options.axisY.type === undefined) { + valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } } // Projected 0 point @@ -252,20 +285,28 @@ // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + valueAxis.projectValue(value.x || 0, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value.y || 0, labelAxisValueIndex, data.normalized[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + labelAxis.projectValue(value.x || 0, labelAxisValueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value.y || 0, valueIndex, data.normalized[seriesIndex]) } } - // Offset to center bar between grid lines - projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); - // Using bi-polar offset for multiple series if no stacked bars or series distribution is used - projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + // If the label axis is a step based axis we will offset the bar into the middle of between two steps using + // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using + // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not + // add any automated positioning. + if(labelAxis instanceof Chartist.StepAxis) { + // Offset to center bar between grid lines, but only if the step axis is not stretched + if(!labelAxis.options.stretch) { + projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); + } + // Using bi-polar offset for multiple series if no stacked bars or series distribution is used + projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + } // Enter value in stacked bar values used to remember previous screen value for stacking up bars previousStack = stackedBarValues[valueIndex] || zeroPoint; @@ -283,8 +324,15 @@ positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; + // Limit x and y so that they are within the chart rect + positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); + positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2); + positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); + positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); + + // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': value, + 'value': value.x === undefined ? value.y : value.x + ',' + value.y, 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); diff --git a/src/scripts/core.js b/src/scripts/core.js index 7b790795..b000c86e 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -355,12 +355,22 @@ var Chartist = { return recursiveConvert(value.value); } else { if(multi) { - return { - x: Chartist.getNumberOrUndefined(value.x), - // Single series value arrays are assumed to specify the Y-Axis value - // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] - y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value) - }; + var multiValue = {}; + + // Single series value arrays are assumed to specify the Y-Axis value + // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] + // If multi is a string then it's assumed that it specified which dimension should be filled as default + if(typeof multi === 'string') { + multiValue[multi] = Chartist.getNumberOrUndefined(value); + } else { + multiValue.y = Chartist.getNumberOrUndefined(value); + } + + multiValue.x = value.hasOwnProperty('x') ? Chartist.getNumberOrUndefined(value.x) : multiValue.x; + multiValue.y = value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : multiValue.y; + + return multiValue; + } else { return Chartist.getNumberOrUndefined(value); } @@ -440,7 +450,7 @@ var Chartist = { * * @memberof Chartist.Core * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} options The Object that contains the chart options * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ @@ -451,9 +461,9 @@ var Chartist = { var highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low - }, - findHigh = options.high === undefined, - findLow = options.low === undefined; + }; + var findHigh = options.high === undefined; + var findLow = options.low === undefined; // Function to recursively walk through arrays and find highest and lowest number function recursiveHighLow(data) { @@ -481,6 +491,14 @@ var Chartist = { recursiveHighLow(data); } + // Overrides of high / low based on reference value, it will make sure that the invisible reference value is + // used to generate the chart. This is useful when the chart always needs to contain the position of the + // invisible reference value in the view i.e. for bipolar scales. + if (options.referenceValue || options.referenceValue === 0) { + highLow.high = Math.max(options.referenceValue, highLow.high); + highLow.low = Math.min(options.referenceValue, highLow.low); + } + // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity if (highLow.high <= highLow.low) { @@ -543,7 +561,7 @@ var Chartist = { if(Chartist.isNum(value)) { return +value; } else if(value) { - return value[dimension] || 0; + return value[dimension || 'y'] || 0; } else { return 0; } @@ -594,11 +612,10 @@ var Chartist = { * @param {Number} axisLength The length of the Axis used for * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. * @param {Number} scaleMinSpace The minimum projected length a step should result in - * @param {Number} referenceValue The reference value for the chart. * @param {Boolean} onlyInteger * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue, onlyInteger) { + Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, onlyInteger) { var i, optimizationCounter = 0, newMin, @@ -608,14 +625,6 @@ var Chartist = { low: highLow.low }; - // Overrides of high / low based on reference value, it will make sure that the invisible reference value is - // used to generate the chart. This is useful when the chart always needs to contain the position of the - // invisible reference value in the view i.e. for bipolar scales. - if (referenceValue || referenceValue === 0) { - bounds.high = Math.max(referenceValue, bounds.high); - bounds.low = Math.min(referenceValue, bounds.low); - } - bounds.valueRange = bounds.high - bounds.low; bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); bounds.step = Math.pow(10, bounds.oom); From 8c3298ceff424d5aee78793b019b53da1f3cd515 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 27 Jun 2015 14:09:10 +0200 Subject: [PATCH 293/593] doc: Fixed axis title plugin code and formatting --- site/data/pages/plugins.yml | 2 +- site/examples/example-plugin-axistitle.js | 67 ++++++++++++----------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 2a699c2e..9d3f3d01 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -193,7 +193,7 @@ sections: id: example-plugin-axistitle classes: ct-golden-section intro: > - Create beautiful hand drawn charts using the Chartist Sketchy plugin. + While not a core functionality, this plugin makes it absolutely easy to add axis titles to your chart. - type: table data: rows: diff --git a/site/examples/example-plugin-axistitle.js b/site/examples/example-plugin-axistitle.js index ff974dcf..ed27945b 100644 --- a/site/examples/example-plugin-axistitle.js +++ b/site/examples/example-plugin-axistitle.js @@ -1,36 +1,37 @@ new Chartist.Line('.ct-chart', { - labels: ['0-15', '16-30', '31-45', '46-60', '61-75', '76-90', '91-105', '106-120'], - series: [1, 3, 7, 12, 1, 2, 1, 0] + labels: ['0-15', '16-30', '31-45', '46-60', '61-75', '76-90', '91-105', '106-120'], + series: [[1, 3, 7, 12, 1, 2, 1, 0]] }, { - chartPadding: { - top: 20, - right: 0, - bottom: 20, - left: 0 - }, - axisY: { - onlyInteger: true - }, - plugins: [ - Chartist.plugins.ctAxisTitle({ - axisX: { - axisTitle: 'Time (mins)', - axisClass: 'ct-axis-title', - offset: { - x: 0, - y: 50 - }, - textAnchor: 'middle' - }, - axisY: { - axisTitle: 'Goals', - axisClass: 'ct-axis-title', - offset: { - x: 0, - y: 0 - }, - flipTitle: false - } - }) - ] + chartPadding: { + top: 20, + right: 0, + bottom: 30, + left: 0 + }, + axisY: { + onlyInteger: true + }, + plugins: [ + Chartist.plugins.ctAxisTitle({ + axisX: { + axisTitle: 'Time (mins)', + axisClass: 'ct-axis-title', + offset: { + x: 0, + y: 50 + }, + textAnchor: 'middle' + }, + axisY: { + axisTitle: 'Goals', + axisClass: 'ct-axis-title', + offset: { + x: 0, + y: 0 + }, + textAnchor: 'middle', + flipTitle: false + } + }) + ] }); From c8edd3eba4e1f05cc947259a6d41849f393183c1 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Mon, 27 Jul 2015 13:56:04 -0600 Subject: [PATCH 294/593] Add 'fillHoles' option for line graphs, which continues the line smoothly through data holes --- src/scripts/interpolation.js | 121 ++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index f5127f0c..cad72301 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -12,30 +12,45 @@ /** * This interpolation function does not smooth the path and the result is only containing lines and no curves. * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.none({ + * fillHoles: false + * }) + * }); + * + * * @memberof Chartist.Interpolation * @return {Function} */ - Chartist.Interpolation.none = function() { + Chartist.Interpolation.none = function(options) { + var defaultOptions = { + fillHoles: false, + }; + options = Chartist.extend({}, defaultOptions, options); return function none(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); - // We need to assume that the first value is a "hole" var hole = true; - for(var i = 1; i < pathCoordinates.length; i += 2) { - var data = valueData[(i - 1) / 2]; + for(var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var currData = valueData[i / 2]; + + if(currData.value !== undefined) { - // If the current value is undefined we should treat it as a hole start - if(data.value === undefined) { - hole = true; - } else { - // If this value is valid we need to check if we're coming out of a hole if(hole) { - // If we are coming out of a hole we should first make a move and also reset the hole flag - path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data); - hole = false; + path.move(currX, currY, false, currData); } else { - path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data); + path.line(currX, currY, false, currData); } + + hole = false; + } else if(!options.fillHoles) { + hole = true; } } @@ -56,7 +71,8 @@ * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.simple({ - * divisor: 2 + * divisor: 2, + * fillHoles: false * }) * }); * @@ -67,7 +83,8 @@ */ Chartist.Interpolation.simple = function(options) { var defaultOptions = { - divisor: 2 + divisor: 2, + fillHoles: false, }; options = Chartist.extend({}, defaultOptions, options); @@ -75,26 +92,19 @@ return function simple(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); - var hole = true; + var prevX, prevY, prevData; - for(var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2]; - var prevY = pathCoordinates[i - 1]; + for(var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; var currY = pathCoordinates[i + 1]; var length = (currX - prevX) * d; - var prevData = valueData[(i / 2) - 1]; var currData = valueData[i / 2]; - if(prevData.value === undefined) { - hole = true; - } else { + if(currData.value !== undefined) { - if(hole) { - path.move(prevX, prevY, false, prevData); - } - - if(currData.value !== undefined) { + if(prevData === undefined) { + path.move(currX, currY, false, currData); + } else { path.curve( prevX + length, prevY, @@ -105,9 +115,13 @@ false, currData ); - - hole = false; } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if(!options.fillHoles) { + prevX = currX = prevData = undefined; } } @@ -128,7 +142,8 @@ * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.cardinal({ - * tension: 1 + * tension: 1, + * fillHoles: false * }) * }); * @@ -138,7 +153,8 @@ */ Chartist.Interpolation.cardinal = function(options) { var defaultOptions = { - tension: 1 + tension: 1, + fillHoles: false, }; options = Chartist.extend({}, defaultOptions, options); @@ -156,7 +172,9 @@ for(var i = 0; i < pathCoordinates.length; i += 2) { // If this value is a "hole" we set the hole flag if(valueData[i / 2].value === undefined) { - hole = true; + if(!options.fillHoles) { + hole = true; + } } else { // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment if(hole) { @@ -258,7 +276,8 @@ * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.step({ - * postpone: true + * postpone: true, + * fillHoles: false * }) * }); * @@ -268,7 +287,8 @@ */ Chartist.Interpolation.step = function(options) { var defaultOptions = { - postpone: true + postpone: true, + fillHoles: false, }; options = Chartist.extend({}, defaultOptions, options); @@ -277,25 +297,18 @@ var path = new Chartist.Svg.Path(); var hole = true; - for (var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2]; - var prevY = pathCoordinates[i - 1]; + var prevX, prevY, prevData; + + for (var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; var currY = pathCoordinates[i + 1]; - var prevData = valueData[(i / 2) - 1]; var currData = valueData[i / 2]; - // If last point is a "hole" - if(prevData.value === undefined) { - hole = true; - } else { - // If last point is not a "hole" but we just came back out of a "hole" we need to move first - if(hole) { - path.move(prevX, prevY, false, prevData); - } - - // If the current point is also not a hole we can draw the step lines - if(currData.value !== undefined) { + // If the current point is also not a hole we can draw the step lines + if(currData.value !== undefined) { + if(prevData === undefined) { + path.move(currX, currY, false, currData); + } else { if(options.postpone) { // If postponed we should draw the step line with the value of the previous value path.line(currX, prevY, false, prevData); @@ -305,9 +318,13 @@ } // Line to the actual point (this should only be a Y-Axis movement path.line(currX, currY, false, currData); - // Reset the "hole" flag as previous and current point have valid values - hole = false; } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if(!options.fillHoles) { + prevX = prevY = prevData = undefined; } } From 48a229fdb35251b53cda8c2f6a0baa278739830b Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Mon, 27 Jul 2015 15:02:21 -0600 Subject: [PATCH 295/593] Update site to included 'filled holes' example --- site/data/pages/examples.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index a6d45f73..8e207f65 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -19,6 +19,15 @@ sections: Chartist does not freak out if you have holes in your data. Instead it will render the lines in segments and handles these holes gracefully. This also allows you to introduce a line at a later point or to terminate the series before others. + - type: live-example + data: + title: Filled holes in data + level: 4 + id: example-line-data-fill-holes + classes: ct-golden-section + intro: > + Sometimes you don't want your data looking so fragmented, even when it really is. That's why you + can also configure Chartist to smooth over holes in your data. - type: live-example data: title: Only whole numbers From 3f123b7a1411620f331fad053aee8b9101383be4 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Mon, 27 Jul 2015 15:02:55 -0600 Subject: [PATCH 296/593] Commit new example example-line-data-fill-holes.js --- site/examples/example-line-data-fill-holes.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 site/examples/example-line-data-fill-holes.js diff --git a/site/examples/example-line-data-fill-holes.js b/site/examples/example-line-data-fill-holes.js new file mode 100644 index 00000000..6c8e74b1 --- /dev/null +++ b/site/examples/example-line-data-fill-holes.js @@ -0,0 +1,17 @@ +var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + series: [ + [5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9], + [10, 15, null, 12, null, 10, 12, 15, null, null, 12, null, 14, null, null, null], + [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null] + ] +}, { + fullWidth: true, + chartPadding: { + right: 10 + }, + lineSmooth: Chartist.Interpolation.cardinal({ + fillHoles: true, + }), + low: 0 +}); From 94b34d28c5368e66bc4c2d627c913b11f5246d86 Mon Sep 17 00:00:00 2001 From: erikmaarten Date: Fri, 31 Jul 2015 19:24:07 +0200 Subject: [PATCH 297/593] [minor] Fix typo in description distributed across the while axis length -> distributed across the whole axis length --- src/scripts/axes/step-axis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index 383728d7..014a4883 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -1,5 +1,5 @@ /** - * 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 while 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. + * 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. * **Options** * 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. * ```javascript From c65a6636a0ff376552a33e3d222b82bdbebeb269 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 2 Aug 2015 22:34:09 +0200 Subject: [PATCH 298/593] Added better handling for multi values when writing custom attributes, fixes #379 --- src/scripts/charts/bar.js | 7 ++++++- src/scripts/charts/line.js | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 1bae0dee..d8b283a0 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -330,9 +330,14 @@ positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); + // For flipped axis we need to normalize the value X and Y values + ; + // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': value.x === undefined ? value.y : value.x + ',' + value.y, + 'value': [value.x, value.y].filter(function(v) { + return v; + }).join(','), 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index bccdbf74..44805130 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -205,7 +205,9 @@ x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y, + 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { + return v; + }).join(','), 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); From ed88a449207b03ef18c4ced5442ca0f0add2a737 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 2 Aug 2015 23:26:24 +0200 Subject: [PATCH 299/593] Version 0.9.2 publish --- CHANGELOG.md | 7 ++ dist/chartist.js | 182 +++++++++++++++++++++++++++------------ dist/chartist.min.js | 6 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- 5 files changed, 138 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 577f9777..874d5903 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v0.9.2 - 2 Aug 2015 +-------------------- +- Enabled bar charts to use dynamic axes fixes #363, fixes #355 +- Added axis title plugin to plugins page (Thanks to @alexstanbury !) +- Added a label group for Pie charts to prevent occlusion by slices (Thanks to Anthony Jimenez!) +- Added better handling for multi values when writing custom attributes, fixes #379 + v0.9.1 - 24 Jun 2015 -------------------- - Fixed bug with areaBase narrowing process in area charts, fixes #364 diff --git a/dist/chartist.js b/dist/chartist.js index 4df27a0b..e4cd81eb 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.1 +/* Chartist.js 0.9.2 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.1' + version: '0.9.2' }; (function (window, document, Chartist) { @@ -376,12 +376,22 @@ var Chartist = { return recursiveConvert(value.value); } else { if(multi) { - return { - x: Chartist.getNumberOrUndefined(value.x), - // Single series value arrays are assumed to specify the Y-Axis value - // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] - y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value) - }; + var multiValue = {}; + + // Single series value arrays are assumed to specify the Y-Axis value + // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] + // If multi is a string then it's assumed that it specified which dimension should be filled as default + if(typeof multi === 'string') { + multiValue[multi] = Chartist.getNumberOrUndefined(value); + } else { + multiValue.y = Chartist.getNumberOrUndefined(value); + } + + multiValue.x = value.hasOwnProperty('x') ? Chartist.getNumberOrUndefined(value.x) : multiValue.x; + multiValue.y = value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : multiValue.y; + + return multiValue; + } else { return Chartist.getNumberOrUndefined(value); } @@ -461,7 +471,7 @@ var Chartist = { * * @memberof Chartist.Core * @param {Array} data The array that contains the data to be visualized in the chart - * @param {Object} options The Object that contains all the optional values for the chart + * @param {Object} options The Object that contains the chart options * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ @@ -472,9 +482,9 @@ var Chartist = { var highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low - }, - findHigh = options.high === undefined, - findLow = options.low === undefined; + }; + var findHigh = options.high === undefined; + var findLow = options.low === undefined; // Function to recursively walk through arrays and find highest and lowest number function recursiveHighLow(data) { @@ -502,6 +512,14 @@ var Chartist = { recursiveHighLow(data); } + // Overrides of high / low based on reference value, it will make sure that the invisible reference value is + // used to generate the chart. This is useful when the chart always needs to contain the position of the + // invisible reference value in the view i.e. for bipolar scales. + if (options.referenceValue || options.referenceValue === 0) { + highLow.high = Math.max(options.referenceValue, highLow.high); + highLow.low = Math.min(options.referenceValue, highLow.low); + } + // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity if (highLow.high <= highLow.low) { @@ -564,7 +582,7 @@ var Chartist = { if(Chartist.isNum(value)) { return +value; } else if(value) { - return value[dimension] || 0; + return value[dimension || 'y'] || 0; } else { return 0; } @@ -615,11 +633,10 @@ var Chartist = { * @param {Number} axisLength The length of the Axis used for * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. * @param {Number} scaleMinSpace The minimum projected length a step should result in - * @param {Number} referenceValue The reference value for the chart. * @param {Boolean} onlyInteger * @return {Object} All the values to set the bounds of the chart */ - Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, referenceValue, onlyInteger) { + Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, onlyInteger) { var i, optimizationCounter = 0, newMin, @@ -629,14 +646,6 @@ var Chartist = { low: highLow.low }; - // Overrides of high / low based on reference value, it will make sure that the invisible reference value is - // used to generate the chart. This is useful when the chart always needs to contain the position of the - // invisible reference value in the view i.e. for bipolar scales. - if (referenceValue || referenceValue === 0) { - bounds.high = Math.max(referenceValue, bounds.high); - bounds.low = Math.min(referenceValue, bounds.low); - } - bounds.valueRange = bounds.high - bounds.low; bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); bounds.step = Math.pow(10, bounds.oom); @@ -2783,7 +2792,7 @@ var Chartist = { function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); - this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.referenceValue, options.onlyInteger); + this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); this.range = { min: this.bounds.min, max: this.bounds.max @@ -2830,7 +2839,7 @@ var Chartist = { 'use strict'; function FixedScaleAxis(axisUnit, data, chartRect, options) { - var highLow = Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return highLow.low + (highLow.high - highLow.low) / this.divisor * index; @@ -3105,7 +3114,9 @@ var Chartist = { x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y, + 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { + return v; + }).join(','), 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); @@ -3414,9 +3425,9 @@ var Chartist = { function createChart(options) { var data = { raw: this.data, - normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) { + normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { return [value]; - }) : Chartist.getDataArray(this.data, options.reverseData) + }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y') }; var highLow; @@ -3437,12 +3448,23 @@ var Chartist = { if(options.stackBars) { // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized, function serialSums() { - return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0); + return Array.prototype.slice.call(arguments).map(function(value) { + return value; + }).reduce(function(prev, curr) { + return { + x: prev.x + curr.x || 0, + y: prev.y + curr.y || 0 + }; + }, {x: 0, y: 0}); }); - highLow = Chartist.getHighLow([serialSums], options); + highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, { + referenceValue: 0 + }), options.horizontalBars ? 'x' : 'y'); } else { - highLow = Chartist.getHighLow(data.normalized, options); + highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, { + referenceValue: 0 + }), options.horizontalBars ? 'x' : 'y'); } // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); @@ -3470,23 +3492,45 @@ var Chartist = { // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { - labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { - ticks: labelAxisTicks - }); + if(options.axisX.type === undefined) { + valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } - valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { - highLow: highLow, - referenceValue: 0 - })); + if(options.axisY.type === undefined) { + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + } } else { - labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { - ticks: labelAxisTicks - }); + if(options.axisX.type === undefined) { + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + } - valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { - highLow: highLow, - referenceValue: 0 - })); + if(options.axisY.type === undefined) { + valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } } // Projected 0 point @@ -3558,20 +3602,28 @@ var Chartist = { // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + valueAxis.projectValue(value.x || 0, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value.y || 0, labelAxisValueIndex, data.normalized[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + labelAxis.projectValue(value.x || 0, labelAxisValueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value.y || 0, valueIndex, data.normalized[seriesIndex]) } } - // Offset to center bar between grid lines - projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); - // Using bi-polar offset for multiple series if no stacked bars or series distribution is used - projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + // If the label axis is a step based axis we will offset the bar into the middle of between two steps using + // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using + // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not + // add any automated positioning. + if(labelAxis instanceof Chartist.StepAxis) { + // Offset to center bar between grid lines, but only if the step axis is not stretched + if(!labelAxis.options.stretch) { + projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); + } + // Using bi-polar offset for multiple series if no stacked bars or series distribution is used + projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + } // Enter value in stacked bar values used to remember previous screen value for stacking up bars previousStack = stackedBarValues[valueIndex] || zeroPoint; @@ -3589,8 +3641,20 @@ var Chartist = { positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; + // Limit x and y so that they are within the chart rect + positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); + positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2); + positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); + positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); + + // For flipped axis we need to normalize the value X and Y values + ; + + // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': value, + 'value': [value.x, value.y].filter(function(v) { + return v; + }).join(','), 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); @@ -3752,6 +3816,7 @@ var Chartist = { */ function createChart(options) { var seriesGroups = [], + labelsGroup, chartRect, radius, labelRadius, @@ -3801,6 +3866,11 @@ var Chartist = { return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; + //if we need to show labels we create the label group now + if(options.showLabel) { + labelsGroup = this.svg.elem('g', null, null, true); + } + // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { @@ -3881,7 +3951,7 @@ var Chartist = { interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); if(interpolatedValue || interpolatedValue === 0) { - var labelElement = seriesGroups[i].elem('text', { + var labelElement = labelsGroup.elem('text', { dx: labelPosition.x, dy: labelPosition.y, 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) @@ -3891,7 +3961,7 @@ var Chartist = { this.eventEmitter.emit('draw', { type: 'label', index: i, - group: seriesGroups[i], + group: labelsGroup, element: labelElement, text: '' + interpolatedValue, x: labelPosition.x, diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 57e8d488..f3346b19 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.9.1 +/* Chartist.js 0.9.2 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.1"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&cl,n=f?c.rho(k.range):0;if(f&&c.projectLength(a,1,k)>=d)k.step=1;else if(f&&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,f&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(h=k.min,i=k.max;h+k.step<=k.low;)h+=k.step;for(;i-k.step>=k.high;)i-=k.step;for(k.min=h,k.max=i,k.range=k.max-k.min,k.values=[],g=k.min;g<=k.max;g+=k.step)k.values.push(c.roundWithPrecision(g));return 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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData).map(function(a){return[a]}):c.getDataArray(this.data,a.reverseData)};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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).reduce(c.sum,0)});b=c.getHighLow([i],a)}else b=c.getHighLow(d.normalized,a);b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(l=n=new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}),j=m=new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0}))):(l=m=new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}),j=n=new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g||0,k,d.normalized[e]),y:o.y1-l.projectValue(g||0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g||0,s,d.normalized[e]),y:o.y1-j.projectValue(g||0,k,d.normalized[e])},m[l.units.pos]+=f*(a.horizontalBars?-1:1),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],n=h.elem("line",t,a.classNames.bar).attr({value:g,meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=a.startAngle,k=c.getDataArray(this.data,a.reverseData);this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),b=c.createChartRect(this.svg,a,g.padding),e=Math.min(b.width()/2,b.height()/2),h=a.total||k.reduce(function(a,b){return a+b},0),e-=a.donut?a.donutWidth/2:0,f="outside"===a.labelPosition||a.donut?e:"center"===a.labelPosition?0:e/2,f+=a.labelOffset;for(var l={x:b.x1+b.width()/2,y:b.y2+b.height()/2},m=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length,n=0;n180,0,q.x,q.y);a.donut||s.line(l.x,l.y);var t=i[n].elem("path",{d:s.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(t.attr({value:k[n],meta:c.serialize(o.meta)},c.xmlNs.uri),a.donut&&t.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:k[n],totalDataSum:h,index:n,meta:o.meta,series:o,group:i[n],element:t,path:s.clone(),center:l,radius:e,startAngle:j,endAngle:p}),a.showLabel){var u=c.polarToCartesian(l.x,l.y,f,j+(p-j)/2),v=a.labelInterpolationFnc(this.data.labels?this.data.labels[n]:k[n],n);if(v||0===v){var w=i[n].elem("text",{dx:u.x,dy:u.y,"text-anchor":d(l,u,a.labelDirection)},a.classNames.label).text(""+v);this.eventEmitter.emit("draw",{type:"label",index:n,group:i[n],element:w,text:""+v,x:u.x,y:u.y})}}j=p}this.eventEmitter.emit("created",{chartRect:b,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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.2"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g.x||0,k,d.normalized[e]),y:o.y1-l.projectValue(g.y||0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g.x||0,s,d.normalized[e]),y:o.y1-j.projectValue(g.y||0,k,d.normalized[e])},l instanceof c.StepAxis&&(l.options.stretch||(m[l.units.pos]+=f*(a.horizontalBars?-1:1)),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],t.x1=Math.min(Math.max(t.x1,o.x1),o.x2),t.x2=Math.min(Math.max(t.x2,o.x1),o.x2),t.y1=Math.min(Math.max(t.y1,o.y2),o.y1),t.y2=Math.min(Math.max(t.y2,o.y2),o.y1),n=h.elem("line",t,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k, +meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.reduce(function(a,b){return a+b},0),f-=a.donut?a.donutWidth/2:0,h="outside"===a.labelPosition||a.donut?f:"center"===a.labelPosition?0:f/2,h+=a.labelOffset;var m={x:e.x1+e.width()/2,y:e.y2+e.height()/2},n=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var o=0;o180,0,r.x,r.y);a.donut||t.line(m.x,m.y);var u=j[o].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(u.attr({value:l[o],meta:c.serialize(p.meta)},c.xmlNs.uri),a.donut&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[o],totalDataSum:i,index:o,meta:p.meta,series:p,group:j[o],element:u,path:t.clone(),center:m,radius:f,startAngle:k,endAngle:q}),a.showLabel){var v=c.polarToCartesian(m.x,m.y,h,k+(q-k)/2),w=a.labelInterpolationFnc(this.data.labels?this.data.labels[o]:l[o],o);if(w||0===w){var x=b.elem("text",{dx:v.x,dy:v.y,"text-anchor":d(m,v,a.labelDirection)},a.classNames.label).text(""+w);this.eventEmitter.emit("draw",{type:"label",index:o,group:b,element:x,text:""+w,x:v.x,y:v.y})}}k=q}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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 1f9b081c..418aabc2 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","x","getNumberOrUndefined","y","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","referenceValue","onlyInteger","newMin","newMax","optimizationCounter","min","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","Bar","determineAnchorPosition","center","direction","toTheRight","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.1\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.1'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\n if(multi) {\n return {\n x: Chartist.getNumberOrUndefined(value.x),\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 y: value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : Chartist.getNumberOrUndefined(value)\n };\n } else {\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 ? Chartist.serialize(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.stripUnit(options.height) || 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 all the optional values for the chart\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 findHigh = options.high === undefined,\n 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 // 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension] || 0;\n } else {\n return 0;\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 {Number} referenceValue The reference value for the chart.\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, referenceValue, onlyInteger) {\n var i,\n optimizationCounter = 0,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\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 (referenceValue || referenceValue === 0) {\n bounds.high = Math.max(referenceValue, bounds.high);\n bounds.low = Math.min(referenceValue, bounds.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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, options, axisUnit.pos);\n this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.referenceValue, 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 = Chartist.getHighLow(data.normalized, 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.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 while 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': pathElement.data.value.x === undefined ? pathElement.data.value.y : pathElement.data.value.x + ',' + pathElement.data.value.y,\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData).map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData)\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, function serialSums() {\n return Array.prototype.slice.call(arguments).reduce(Chartist.sum, 0);\n });\n\n highLow = Chartist.getHighLow([serialSums], options);\n } else {\n highLow = Chartist.getHighLow(data.normalized, options);\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.raw.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.raw.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 labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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 || 0, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value || 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value || 0, valueIndex, data.normalized[seriesIndex])\n }\n }\n\n // Offset to center bar between grid lines\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\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 // 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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\n\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': value,\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = seriesGroups[i].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: i,\n group: seriesGroups[i],\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.2\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.2'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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.stripUnit(options.height) || 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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.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 while 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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.x || 0, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value.y || 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value.x || 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value.y || 0, valueIndex, data.normalized[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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\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 // For flipped axis we need to normalize the value X and Y values\n ;\n\n // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/package.json b/package.json index adbff413..058c6495 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.1", + "version": "0.9.2", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 61d7e54237c45f7fa238a84dd20b9314120375e2 Mon Sep 17 00:00:00 2001 From: Markus Gruber Date: Wed, 5 Aug 2015 16:14:00 +0200 Subject: [PATCH 300/593] Fix typo in hasFeature string --- src/scripts/svg.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 03c48443..09c0141b 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -533,7 +533,7 @@ * @return {Boolean} True of false if the feature is supported or not */ Chartist.Svg.isSupported = function(feature) { - return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); + return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1'); }; /** From 19575b97316108476848626963bd05383a8f7cf0 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 5 Aug 2015 22:40:44 +0200 Subject: [PATCH 301/593] Added better check for undefined values in bar chart, fixes #400 --- site/templates/test.hbs | 17 +++++++++++++++++ src/scripts/charts/bar.js | 11 ++++------- 2 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 site/templates/test.hbs diff --git a/site/templates/test.hbs b/site/templates/test.hbs new file mode 100644 index 00000000..c9292d4f --- /dev/null +++ b/site/templates/test.hbs @@ -0,0 +1,17 @@ +

    + + diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index d8b283a0..27c96676 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -285,13 +285,13 @@ // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value.x || 0, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - labelAxis.projectValue(value.y || 0, labelAxisValueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value.x || 0, labelAxisValueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - valueAxis.projectValue(value.y || 0, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[seriesIndex]) } } @@ -330,9 +330,6 @@ positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); - // For flipped axis we need to normalize the value X and Y values - ; - // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'value': [value.x, value.y].filter(function(v) { From cb6057d191b70b149f49addf6d514412084f361c Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 5 Aug 2015 22:49:42 +0200 Subject: [PATCH 302/593] Version bump to 0.9.3 --- CHANGELOG.md | 7 ++++++- dist/chartist.js | 19 ++++++++----------- dist/chartist.min.js | 6 +++--- dist/chartist.min.js.map | 2 +- package.json | 2 +- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 874d5903..3e160c0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ -v0.9.2 - 2 Aug 2015 +v0.9.3 - 05 Aug 2015 +-------------------- +- Added better check for undefined values in bar chart, fixes #400 +- Fixed issue with SVG feature check within Svg module (Thanks to Markus Gruber !) + +v0.9.2 - 02 Aug 2015 -------------------- - Enabled bar charts to use dynamic axes fixes #363, fixes #355 - Added axis title plugin to plugins page (Thanks to @alexstanbury !) diff --git a/dist/chartist.js b/dist/chartist.js index e4cd81eb..5fe3123e 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.2 +/* Chartist.js 0.9.3 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.2' + version: '0.9.3' }; (function (window, document, Chartist) { @@ -2184,7 +2184,7 @@ var Chartist = { * @return {Boolean} True of false if the feature is supported or not */ Chartist.Svg.isSupported = function(feature) { - return document.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#' + feature, '1.1'); + return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1'); }; /** @@ -2869,7 +2869,7 @@ var Chartist = { }(window, document, Chartist)); ;/** - * 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 while 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. + * 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. * **Options** * 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. * ```javascript @@ -3602,13 +3602,13 @@ var Chartist = { // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value.x || 0, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - labelAxis.projectValue(value.y || 0, labelAxisValueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value.x || 0, labelAxisValueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - valueAxis.projectValue(value.y || 0, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[seriesIndex]) } } @@ -3647,9 +3647,6 @@ var Chartist = { positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); - // For flipped axis we need to normalize the value X and Y values - ; - // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'value': [value.x, value.y].filter(function(v) { diff --git a/dist/chartist.min.js b/dist/chartist.min.js index f3346b19..7002d6d1 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.9.2 +/* Chartist.js 0.9.3 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.2"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g.x||0,k,d.normalized[e]),y:o.y1-l.projectValue(g.y||0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g.x||0,s,d.normalized[e]),y:o.y1-j.projectValue(g.y||0,k,d.normalized[e])},l instanceof c.StepAxis&&(l.options.stretch||(m[l.units.pos]+=f*(a.horizontalBars?-1:1)),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],t.x1=Math.min(Math.max(t.x1,o.x1),o.x2),t.x2=Math.min(Math.max(t.x2,o.x1),o.x2),t.y1=Math.min(Math.max(t.y1,o.y2),o.y1),t.y2=Math.min(Math.max(t.y2,o.y2),o.y1),n=h.elem("line",t,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k, -meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.reduce(function(a,b){return a+b},0),f-=a.donut?a.donutWidth/2:0,h="outside"===a.labelPosition||a.donut?f:"center"===a.labelPosition?0:f/2,h+=a.labelOffset;var m={x:e.x1+e.width()/2,y:e.y2+e.height()/2},n=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var o=0;o180,0,r.x,r.y);a.donut||t.line(m.x,m.y);var u=j[o].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(u.attr({value:l[o],meta:c.serialize(p.meta)},c.xmlNs.uri),a.donut&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[o],totalDataSum:i,index:o,meta:p.meta,series:p,group:j[o],element:u,path:t.clone(),center:m,radius:f,startAngle:k,endAngle:q}),a.showLabel){var v=c.polarToCartesian(m.x,m.y,h,k+(q-k)/2),w=a.labelInterpolationFnc(this.data.labels?this.data.labels[o]:l[o],o);if(w||0===w){var x=b.elem("text",{dx:v.x,dy:v.y,"text-anchor":d(m,v,a.labelDirection)},a.classNames.label).text(""+w);this.eventEmitter.emit("draw",{type:"label",index:o,group:b,element:x,text:""+w,x:v.x,y:v.y})}}k=q}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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g&&g.x?g.x:0,k,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,s,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[e])},l instanceof c.StepAxis&&(l.options.stretch||(m[l.units.pos]+=f*(a.horizontalBars?-1:1)),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],t.x1=Math.min(Math.max(t.x1,o.x1),o.x2),t.x2=Math.min(Math.max(t.x2,o.x1),o.x2),t.y1=Math.min(Math.max(t.y1,o.y2),o.y1),t.y2=Math.min(Math.max(t.y2,o.y2),o.y1),n=h.elem("line",t,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({ +type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.reduce(function(a,b){return a+b},0),f-=a.donut?a.donutWidth/2:0,h="outside"===a.labelPosition||a.donut?f:"center"===a.labelPosition?0:f/2,h+=a.labelOffset;var m={x:e.x1+e.width()/2,y:e.y2+e.height()/2},n=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var o=0;o180,0,r.x,r.y);a.donut||t.line(m.x,m.y);var u=j[o].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(u.attr({value:l[o],meta:c.serialize(p.meta)},c.xmlNs.uri),a.donut&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[o],totalDataSum:i,index:o,meta:p.meta,series:p,group:j[o],element:u,path:t.clone(),center:m,radius:f,startAngle:k,endAngle:q}),a.showLabel){var v=c.polarToCartesian(m.x,m.y,h,k+(q-k)/2),w=a.labelInterpolationFnc(this.data.labels?this.data.labels[o]:l[o],o);if(w||0===w){var x=b.elem("text",{dx:v.x,dy:v.y,"text-anchor":d(m,v,a.labelDirection)},a.classNames.label).text(""+w);this.eventEmitter.emit("draw",{type:"label",index:o,group:b,element:x,text:""+w,x:v.x,y:v.y})}}k=q}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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 418aabc2..2f22e7f0 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.2\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.2'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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.stripUnit(options.height) || 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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('www.http://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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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.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 while 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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.x || 0, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value.y || 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value.x || 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value.y || 0, valueIndex, data.normalized[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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\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 // For flipped axis we need to normalize the value X and Y values\n ;\n\n // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.3\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.3'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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.stripUnit(options.height) || 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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.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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/package.json b/package.json index 058c6495..b59da555 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.2", + "version": "0.9.3", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From ae68b0deb6a05d86a17f0bbcf5e9d07537d411b9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 6 Aug 2015 10:49:19 +0200 Subject: [PATCH 303/593] Added axes to all events where available --- src/scripts/charts/bar.js | 2 ++ src/scripts/charts/line.js | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 27c96676..31ca89b3 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -345,6 +345,8 @@ meta: Chartist.getMetaData(series, valueIndex), series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, chartRect: chartRect, group: seriesElement, element: bar diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 44805130..00616e04 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -218,6 +218,8 @@ meta: pathElement.data.meta, series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, group: seriesElement, element: point, x: pathElement.x, @@ -239,6 +241,8 @@ index: seriesIndex, series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, group: seriesElement, element: line }); @@ -290,6 +294,8 @@ path: areaPath.clone(), series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, chartRect: chartRect, index: seriesIndex, group: seriesElement, From dd3fe00a6b72f9dcddb43a91f39210bbaa73d47e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 6 Aug 2015 10:51:10 +0200 Subject: [PATCH 304/593] Also respect additional parameters when creating SVG Element with existing DOM element --- src/scripts/svg.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 09c0141b..96c949cc 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -39,21 +39,21 @@ if(name === 'svg') { this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); } + } - if(attributes) { - this.attr(attributes); - } + if(attributes) { + this.attr(attributes); + } - if(className) { - this.addClass(className); - } + if(className) { + this.addClass(className); + } - if(parent) { - if (insertFirst && parent._node.firstChild) { - parent._node.insertBefore(this._node, parent._node.firstChild); - } else { - parent._node.appendChild(this._node); - } + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); } } } From 60e94d35e2e023f90e14b8907eb1115c9270e7ad Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 6 Aug 2015 10:52:31 +0200 Subject: [PATCH 305/593] Removed test file from doc site --- site/templates/test.hbs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 site/templates/test.hbs diff --git a/site/templates/test.hbs b/site/templates/test.hbs deleted file mode 100644 index c9292d4f..00000000 --- a/site/templates/test.hbs +++ /dev/null @@ -1,17 +0,0 @@ -
    - - From fbf1f37dc360f668025322134c1ac8a933e280c2 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 6 Aug 2015 10:55:56 +0200 Subject: [PATCH 306/593] Version bump to 0.7.4 --- CHANGELOG.md | 5 +++++ dist/chartist.js | 36 ++++++++++++++++++++++-------------- dist/chartist.min.js | 6 +++--- dist/chartist.min.js.map | 2 +- package.json | 2 +- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e160c0b..efb142d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v0.9.4 - 06 Aug 2015 +-------------------- +- Added axes to all events where they are available in context to provide better API convenience when developing plugins +- Consider additional parameters of SVG elem when called with DOM node + v0.9.3 - 05 Aug 2015 -------------------- - Added better check for undefined values in bar chart, fixes #400 diff --git a/dist/chartist.js b/dist/chartist.js index 5fe3123e..5c5b9310 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.3 +/* Chartist.js 0.9.4 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.3' + version: '0.9.4' }; (function (window, document, Chartist) { @@ -1690,21 +1690,21 @@ var Chartist = { if(name === 'svg') { this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); } + } - if(attributes) { - this.attr(attributes); - } + if(attributes) { + this.attr(attributes); + } - if(className) { - this.addClass(className); - } + if(className) { + this.addClass(className); + } - if(parent) { - if (insertFirst && parent._node.firstChild) { - parent._node.insertBefore(this._node, parent._node.firstChild); - } else { - parent._node.appendChild(this._node); - } + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); } } } @@ -3127,6 +3127,8 @@ var Chartist = { meta: pathElement.data.meta, series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, group: seriesElement, element: point, x: pathElement.x, @@ -3148,6 +3150,8 @@ var Chartist = { index: seriesIndex, series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, group: seriesElement, element: line }); @@ -3199,6 +3203,8 @@ var Chartist = { path: areaPath.clone(), series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, chartRect: chartRect, index: seriesIndex, group: seriesElement, @@ -3662,6 +3668,8 @@ var Chartist = { meta: Chartist.getMetaData(series, valueIndex), series: series, seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, chartRect: chartRect, group: seriesElement, element: bar diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 7002d6d1..b69e4846 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.9.3 +/* Chartist.js 0.9.4 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.3"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(d){var e=i.elem("path",{d:d.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:d.clone(),series:f,seriesIndex:g,chartRect:j,index:g,group:i,element:e})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[e].forEach(function(g,k){var m,n,r,s;if(s=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,m=a.horizontalBars?{x:o.x1+j.projectValue(g&&g.x?g.x:0,k,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,s,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,s,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[e])},l instanceof c.StepAxis&&(l.options.stretch||(m[l.units.pos]+=f*(a.horizontalBars?-1:1)),m[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),r=q[k]||p,q[k]=r-(p-m[l.counterUnits.pos]),void 0!==g){var t={};t[l.units.pos+"1"]=m[l.units.pos],t[l.units.pos+"2"]=m[l.units.pos],t[l.counterUnits.pos+"1"]=a.stackBars?r:p,t[l.counterUnits.pos+"2"]=a.stackBars?q[k]:m[l.counterUnits.pos],t.x1=Math.min(Math.max(t.x1,o.x1),o.x2),t.x2=Math.min(Math.max(t.x2,o.x1),o.x2),t.y1=Math.min(Math.max(t.y1,o.y2),o.y1),t.y2=Math.min(Math.max(t.y2,o.y2),o.y1),n=h.elem("line",t,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({ -type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,seriesIndex:e,chartRect:o,group:h,element:n},t))}}.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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.reduce(function(a,b){return a+b},0),f-=a.donut?a.donutWidth/2:0,h="outside"===a.labelPosition||a.donut?f:"center"===a.labelPosition?0:f/2,h+=a.labelOffset;var m={x:e.x1+e.width()/2,y:e.y2+e.height()/2},n=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var o=0;o180,0,r.x,r.y);a.donut||t.line(m.x,m.y);var u=j[o].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(u.attr({value:l[o],meta:c.serialize(p.meta)},c.xmlNs.uri),a.donut&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[o],totalDataSum:i,index:o,meta:p.meta,series:p,group:j[o],element:u,path:t.clone(),center:m,radius:f,startAngle:k,endAngle:q}),a.showLabel){var v=c.polarToCartesian(m.x,m.y,h,k+(q-k)/2),w=a.labelInterpolationFnc(this.data.labels?this.data.labels[o]:l[o],o);if(w||0===w){var x=b.elem("text",{dx:v.x,dy:v.y,"text-anchor":d(m,v,a.labelDirection)},a.classNames.label).text(""+w);this.eventEmitter.emit("draw",{type:"label",index:o,group:b,element:x,text:""+w,x:v.x,y:v.y})}}k=q}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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.4"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(h){var k=i.elem("path",{d:h.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:h.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:k})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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],v[l.counterUnits.pos+"1"]=a.stackBars?t:p,v[l.counterUnits.pos+"2"]=a.stackBars?q[k]:r[l.counterUnits.pos],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),s=h.elem("line",v,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri), +this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.reduce(function(a,b){return a+b},0),f-=a.donut?a.donutWidth/2:0,h="outside"===a.labelPosition||a.donut?f:"center"===a.labelPosition?0:f/2,h+=a.labelOffset;var m={x:e.x1+e.width()/2,y:e.y2+e.height()/2},n=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var o=0;o180,0,r.x,r.y);a.donut||t.line(m.x,m.y);var u=j[o].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(u.attr({value:l[o],meta:c.serialize(p.meta)},c.xmlNs.uri),a.donut&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[o],totalDataSum:i,index:o,meta:p.meta,series:p,group:j[o],element:u,path:t.clone(),center:m,radius:f,startAngle:k,endAngle:q}),a.showLabel){var v=c.polarToCartesian(m.x,m.y,h,k+(q-k)/2),w=a.labelInterpolationFnc(this.data.labels?this.data.labels[o]:l[o],o);if(w||0===w){var x=b.elem("text",{dx:v.x,dy:v.y,"text-anchor":d(m,v,a.labelDirection)},a.classNames.label).text(""+w);this.eventEmitter.emit("draw",{type:"label",index:o,group:b,element:x,text:""+w,x:v.x,y:v.y})}}k=q}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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 2f22e7f0..513c2720 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.3\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.3'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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.stripUnit(options.height) || 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 /**\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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.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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\n series: series,\n seriesIndex: seriesIndex,\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 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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.4\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.4'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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.stripUnit(options.height) || 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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.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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/package.json b/package.json index b59da555..7771c528 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.3", + "version": "0.9.4", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From ffddebc1c819f14d3982af5c185f9f619249020c Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Thu, 6 Aug 2015 12:30:18 +0200 Subject: [PATCH 307/593] Added Chartist threshold plugin to documentation site --- bower.json | 1 + site/data/pages/plugins.yml | 25 +++++++++++++++++++++++ site/examples/example-plugin-threshold.js | 16 +++++++++++++++ site/layouts/default.hbs | 1 + site/partials/live-example.hbs | 2 +- site/styles/_example-charts.scss | 23 +++++++++++++++++++++ 6 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 site/examples/example-plugin-threshold.js diff --git a/bower.json b/bower.json index ef695161..e2e5f63d 100644 --- a/bower.json +++ b/bower.json @@ -16,6 +16,7 @@ "chartist-plugin-accessibility": "~0.0.2", "chartist-plugin-tooltip": "~0.0.8", "chartist-plugin-axistitle": "~0.0.1", + "chartist-plugin-threshold": "~0.0.1", "matchMedia": "~0.2.0" }, "ignore": [ diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 9d3f3d01..0f501c05 100644 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -203,6 +203,31 @@ sections: - - 'Link:' - 'chartist-plugin-axistitle' + - type: sub-section + data: + title: Threshold Plugin + level: 4 + items: + - type: text + data: + text: > + This Chartist plugin can be used to divide your Line or Bar chart with a threshold. + - type: live-example + data: + id: example-plugin-threshold + classes: ct-golden-section + intro: > + Everything above and below the + threshold will be tagged with a special class, in order for your to apply different styling where appropriate. + - type: table + data: + rows: + - + - 'Author:' + - Gion Kunz + - + - 'Link:' + - 'chartist-plugin-threshold' - title: Develop a plugin level: 3 items: diff --git a/site/examples/example-plugin-threshold.js b/site/examples/example-plugin-threshold.js new file mode 100644 index 00000000..835ee57f --- /dev/null +++ b/site/examples/example-plugin-threshold.js @@ -0,0 +1,16 @@ +new Chartist.Line('.ct-chart', { + labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + series: [ + [5, -4, 3, 7, 20, 10, 3, 4, 8, -10, 6, -8] + ] +}, { + showArea: true, + axisY: { + onlyInteger: true + }, + plugins: [ + Chartist.plugins.ctThreshold({ + threshold: 4 + }) + ] +}); diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index f36d516b..60ebea40 100644 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -74,6 +74,7 @@ + diff --git a/site/partials/live-example.hbs b/site/partials/live-example.hbs index 18b56185..2c9c9953 100644 --- a/site/partials/live-example.hbs +++ b/site/partials/live-example.hbs @@ -1,4 +1,4 @@ -
    {{#if title}}
    diff --git a/site/styles/_example-charts.scss b/site/styles/_example-charts.scss index f16dae31..39960c12 100644 --- a/site/styles/_example-charts.scss +++ b/site/styles/_example-charts.scss @@ -53,3 +53,26 @@ @include ct-chart-point($ct-point-size: 20px); } } + +#example-plugin-threshold { + .ct-line { + stroke-dasharray: 5px; + animation: dashoffset 1s linear infinite; + } + + .ct-line.ct-threshold-above, .ct-point.ct-threshold-above, .ct-bar.ct-threshold-above { + stroke: #f05b4f; + } + + .ct-line.ct-threshold-below, .ct-point.ct-threshold-below, .ct-bar.ct-threshold-below { + stroke: #59922b; + } + + .ct-area.ct-threshold-above { + fill: #f05b4f; + } + + .ct-area.ct-threshold-below { + fill: #59922b; + } +} From 5657616bd3a2ba3a22d6933b2d91cb431b1151a1 Mon Sep 17 00:00:00 2001 From: Douglas Mak Date: Mon, 7 Sep 2015 15:33:46 +0900 Subject: [PATCH 308/593] Added an option to allow stacked bars to draw from the zero line --- src/scripts/charts/bar.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 31ca89b3..52689ef8 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -77,7 +77,9 @@ // Specify the distance in pixel of bars in a group seriesBarDistance: 15, // If set to true this property will cause the series bars to be stacked and 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. - stackBars: false, + stackBars: false, + // If set to true this property will cause the series bars to be stacked and force all bars to draw from the zero line. + negativeStackBars: false, // 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. horizontalBars: false, // 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. @@ -321,8 +323,8 @@ positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; - positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; + positions[labelAxis.counterUnits.pos + '1'] = options.stackBars && !options.negativeStackBars ? previousStack : zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = options.stackBars && !options.negativeStackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; // Limit x and y so that they are within the chart rect positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); From f587a8a06b40a4a6514ab92e2ab0b4b762ce267d Mon Sep 17 00:00:00 2001 From: Douglas Mak Date: Tue, 15 Sep 2015 12:56:11 +0900 Subject: [PATCH 309/593] Replaced the previous option (negativeStackBars) for stacked bars drawing from the zero line with stackMode. Currently there are two options: overlap and accumulate. Overlap is the existing function whereas accumulate is the option to draw from the zero line. --- src/scripts/charts/bar.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 52689ef8..7168a9a4 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -76,10 +76,11 @@ }, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, - // If set to true this property will cause the series bars to be stacked and 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. + // If set to true this property will cause the series bars to be stacked. The default stack mode is `accumulate`. stackBars: false, - // If set to true this property will cause the series bars to be stacked and force all bars to draw from the zero line. - negativeStackBars: false, + // If set to 'accumulate' this property will force the stacked bars to draw from the zero line. + // If set to 'overlap' 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. + stackMode: 'overlap', // 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. horizontalBars: false, // 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. @@ -322,9 +323,20 @@ var positions = {}; positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; - // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - positions[labelAxis.counterUnits.pos + '1'] = options.stackBars && !options.negativeStackBars ? previousStack : zeroPoint; - positions[labelAxis.counterUnits.pos + '2'] = options.stackBars && !options.negativeStackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; + + if(options.stackBars && options.stackMode == 'overlap') { + // Stack mode: overlap (default) + // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line + // We want backwards compatibility, so the expected fallback without the 'stackMode' option + // should be the original (overlap) + positions[labelAxis.counterUnits.pos + '1'] = previousStack; + positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; + } else { + // Draw from the zero line normally + // This is also the same code for Stack mode: accumulate + positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; + } // Limit x and y so that they are within the chart rect positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); From d4def88d830b81ca1364edddd2b4f21a9b1b702a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20=C3=96hlschl=C3=A4ger?= Date: Tue, 29 Sep 2015 11:05:47 +0200 Subject: [PATCH 310/593] Added Chartist fill donut plugin to documentation site --- bower.json | 1 + site/data/pages/plugins.yml | 26 ++++++++++ site/examples/example-plugin-fill-donut.js | 56 ++++++++++++++++++++++ site/layouts/default.hbs | 1 + site/styles/_example-charts.scss | 32 +++++++++++++ 5 files changed, 116 insertions(+) mode change 100644 => 100755 bower.json mode change 100644 => 100755 site/data/pages/plugins.yml create mode 100755 site/examples/example-plugin-fill-donut.js mode change 100644 => 100755 site/layouts/default.hbs mode change 100644 => 100755 site/styles/_example-charts.scss diff --git a/bower.json b/bower.json old mode 100644 new mode 100755 index e2e5f63d..ca58e17c --- a/bower.json +++ b/bower.json @@ -17,6 +17,7 @@ "chartist-plugin-tooltip": "~0.0.8", "chartist-plugin-axistitle": "~0.0.1", "chartist-plugin-threshold": "~0.0.1", + "chartist-plugin-fill-donut": "~0.0.1", "matchMedia": "~0.2.0" }, "ignore": [ diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml old mode 100644 new mode 100755 index 0f501c05..20359aa8 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -228,6 +228,32 @@ sections: - - 'Link:' - 'chartist-plugin-threshold' + - type: sub-section + data: + title: FillDonut Plugin + level: 4 + items: + - type: text + data: + text: > + Let animated donuts look filled and provide options for append labels and html to the donut chart. + This plugin draw the donut a second time but without delay and animation, so it animation will overlaps and looks like the fill the donut. + Also your a possible to add multiple html-labels to the donut on different positions. + - type: live-example + data: + id: example-plugin-fill-donut + classes: ct-golden-section + intro: > + Let animated donuts look filled and provide options for append labels and html to the donut chart. + - type: table + data: + rows: + - + - 'Author:' + - Moxx + - + - 'Link:' + - 'chartist-plugin-threshold' - title: Develop a plugin level: 3 items: diff --git a/site/examples/example-plugin-fill-donut.js b/site/examples/example-plugin-fill-donut.js new file mode 100755 index 00000000..ef263d74 --- /dev/null +++ b/site/examples/example-plugin-fill-donut.js @@ -0,0 +1,56 @@ +var chart = new Chartist.Pie('.ct-chart', + { + series: [160, 60 ], + labels: ['', ''] + }, { + donut: true, + donutWidth: 20, + startAngle: 210, + total: 260, + showLabel: false, + plugins: [ + Chartist.plugins.fillDonut({ + items: [{ + content: '', + position: 'bottom', + offsetY : 10, + offsetX: -2 + }, { + content: '

    160mph

    ' + }] + }) + ], + }); + +chart.on('draw', function(data) { + if(data.type === 'slice' && data.index == 0) { + // Get the total path length in order to use for dash array animation + var pathLength = data.element._node.getTotalLength(); + + // Set a dasharray that matches the path length as prerequisite to animate dashoffset + data.element.attr({ + 'stroke-dasharray': pathLength + 'px ' + pathLength + 'px' + }); + + // Create animation definition while also assigning an ID to the animation for later sync usage + var animationDefinition = { + 'stroke-dashoffset': { + id: 'anim' + data.index, + dur: 1200, + from: -pathLength + 'px', + to: '0px', + easing: Chartist.Svg.Easing.easeOutQuint, + fill: 'freeze' + } + }; + + // We need to set an initial value before the animation starts as we are not in guided mode which would do that for us + data.element.attr({ + 'stroke-dashoffset': -pathLength + 'px' + }); + + // We can't use guided mode as the animations need to rely on setting begin manually + // See http://gionkunz.github.io/chartist-js/api-documentation.html#chartistsvg-function-animate + data.element.animate(animationDefinition, true); + } +}); diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs old mode 100644 new mode 100755 index 60ebea40..449b475c --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -75,6 +75,7 @@ + diff --git a/site/styles/_example-charts.scss b/site/styles/_example-charts.scss old mode 100644 new mode 100755 index 39960c12..4b36ea64 --- a/site/styles/_example-charts.scss +++ b/site/styles/_example-charts.scss @@ -76,3 +76,35 @@ fill: #59922b; } } + +#example-plugin-fill-donut { + .ct-chart-donut .ct-series-a .ct-slice-donut { + stroke: #d70206; + } + + .ct-chart-donut .ct-series-b .ct-slice-donut { + stroke: rgba(0,0,0,.4); + opacity: 0.0; + } + + .ct-chart-donut .ct-fill-donut .ct-slice-donut { + stroke: rgba(0,0,0,.4); + opacity: 1; + } + + .ct-fill-donut-label { + h3 { + font-weight: bolder; + } + + small { + font-size: 0.6em; + } + + + i { + font-size: 1.5em; + } + + } +} From 91ff7dc27ddd03eaaf6e3baff81121c25aac0b80 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 14:43:41 +0200 Subject: [PATCH 311/593] Use jQuery from jasmine-jquery dependency in jasmine tests instead of googleapis. --- tasks/jasmine.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/jasmine.js b/tasks/jasmine.js index c3fe2904..4fa2feed 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -31,8 +31,8 @@ module.exports = function (grunt) { options: { specs: '<%= pkg.config.test %>/spec/**/spec-*.js', helpers: '<%= pkg.config.test %>/spec/**/helper-*.js', - vendor: [ - 'http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', + vendor: [ + 'node_modules/jasmine-jquery/vendor/jquery/jquery.js', 'node_modules/jasmine-jquery/lib/jasmine-jquery.js' ], styles: [ From 1ae701f45ba2610f4858d2288879bd556cd6a851 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 15:09:50 +0200 Subject: [PATCH 312/593] Fix gauge chart example id --- site/data/pages/examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 8e207f65..6decec43 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -243,7 +243,7 @@ sections: data: title: Gauge chart level: 4 - id: simple-gauge-chart + id: gauge-chart classes: ct-golden-section ct-negative-labels intro: This pie chart uses donut, startAngle and total to draw a gauge chart. From 759e95a1910b3552b0b363c79557dafe365d1c00 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 15:24:37 +0200 Subject: [PATCH 313/593] Remove unused variable "hole". --- src/scripts/interpolation.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index cad72301..e122a47d 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -295,7 +295,6 @@ return function step(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); - var hole = true; var prevX, prevY, prevData; From 5628b4a9fb0bcd754f51247ad0027bb9c46267a5 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 15:25:00 +0200 Subject: [PATCH 314/593] Add unit tests for simple pie and gauge chart. --- test/spec/spec-pie-chart.js | 149 ++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 834013ea..2cb7602a 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -33,4 +33,153 @@ describe('Pie chart tests', function() { }); }); }); + + describe('Simple Pie Chart', function() { + // https://gionkunz.github.io/chartist-js/examples.html#simple-pie-chart + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var data = { + series: [5, 3, 4] + }; + var options = { + width: 100, + height: 100, + chartPadding: 10, + labelInterpolationFnc: function(value) { + return Math.round(value / data.series.reduce(sum) * 100) + '%'; + } + }; + + var sum = function(a, b) { return a + b }; + + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('should render three slices', function(done) { + onCreated(function() { + expect($('.ct-slice-pie').length).toBe(3); + done(); + }); + }); + + it('should set value attribute', function(done) { + onCreated(function() { + var slices = $('.ct-slice-pie'); + expect(slices.eq(2).attr('ct:value')).toBe('5'); + expect(slices.eq(1).attr('ct:value')).toBe('3'); + expect(slices.eq(0).attr('ct:value')).toBe('4'); + done(); + }); + }); + + it('should create slice path', function(done) { + onCreated(function() { + $('.ct-slice-pie').each(function() { + + var num = '\\d+(\\.\\d*)?'; + var pattern = + '^M' + num + ',' + num + + 'A40,40,0,0,0,' + num + ',' + num + + 'L50,50Z$' + ; + var path = $(this).attr('d'); + expect(path).toMatch(pattern); + }); + done(); + }); + }) + + it('should add labels', function(done) { + onCreated(function() { + var labels = $('.ct-label'); + expect(labels.eq(0).text()).toBe('42%'); + expect(labels.eq(1).text()).toBe('25%'); + expect(labels.eq(2).text()).toBe('33%'); + done(); + }); + + }); + }); + + + + describe('Gauge Chart', function() { + // https://gionkunz.github.io/chartist-js/examples.html#gauge-chart + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var data = { + series: [20, 10, 30, 40] + }; + var options = { + chartPadding:50, + height:500, + width:500, + donut: true, + donutWidth: 60, + startAngle: 270, + total: 200, + showLabel: false + }; + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('should render four strokes', function(done) { + onCreated(function() { + expect($('.ct-slice-donut').length).toBe(4); + done(); + }); + }); + + it('should set value attribute', function(done) { + onCreated(function() { + var slices = $('.ct-slice-donut'); + expect(slices.eq(3).attr('ct:value')).toBe('20'); + expect(slices.eq(2).attr('ct:value')).toBe('10'); + expect(slices.eq(1).attr('ct:value')).toBe('30'); + expect(slices.eq(0).attr('ct:value')).toBe('40'); + done(); + }); + }); + + it('should create slice path', function(done) { + onCreated(function() { + $('.ct-slice-donut').each(function() { + + var num = '\\d+(\\.\\d*)?'; + var pattern = + '^M' + num + ',' + num + + 'A170,170,0,0,0,' + num + ',' + num + + '$' + ; + var path = $(this).attr('d'); + expect(path).toMatch(pattern); + }); + done(); + }); + }) + + it('should set stroke-width', function(done) { + onCreated(function() { + $('.ct-slice-donut').each(function() { + var style = $(this).attr('style'); + expect(style).toMatch('stroke-width:\\s?60px'); + }); + done(); + }); + }); + + it('should not add labels', function(done) { + onCreated(function() { + var labels = $('.ct-label'); + expect(labels.length).toBe(0); + done(); + }); + + }); + + }); }); From 7475b5089c1c1455d48b3472627e370ca88c14ca Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 15:44:37 +0200 Subject: [PATCH 315/593] Add Chartist.quantity --- src/scripts/core.js | 18 ++++++++++++++++++ test/spec/spec-core.js | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/scripts/core.js b/src/scripts/core.js index b000c86e..fe12b062 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -102,6 +102,24 @@ var Chartist = { return value; }; + /** + * Converts a number or string to a quantity object. + * + * @memberof Chartist.Core + * @param {String|Number} input + * @return {Object} Returns an object containing the value and the unit. + */ + Chartist.quantity = function(input) { + if (typeof input === 'string') { + var match = (/^(\d+)\s*(.*)$/g).exec(input); + return { + value : +match[1], + unit: match[2] || undefined + }; + } + return { value: input }; + }; + /** * This is a wrapper around document.querySelector that will return the query if it's already of type Node * diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index f1710da0..5f3b06e5 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -279,4 +279,27 @@ describe('Chartist core', function() { }); }); }); + + fdescribe('quantity', function() { + + it('should return value for numbers', function() { + expect(Chartist.quantity(100)).toEqual({ value: 100 }); + expect(Chartist.quantity(0)).toEqual({ value: 0 }); + expect(Chartist.quantity(NaN)).toEqual({ value: NaN }); + expect(Chartist.quantity(null)).toEqual({ value: null }); + expect(Chartist.quantity(undefined)).toEqual({ value: undefined }); + }); + + it('should return value without unit from string', function() { + expect(Chartist.quantity('100')).toEqual({ value: 100, unit : undefined }); + expect(Chartist.quantity('0')).toEqual({ value: 0, unit : undefined }); + }); + + it('should return value and unit from string', function() { + expect(Chartist.quantity('100%')).toEqual({ value: 100, unit :'%' }); + expect(Chartist.quantity('100 %')).toEqual({ value: 100, unit :'%' }); + expect(Chartist.quantity('0px')).toEqual({ value: 0, unit: 'px' }); + }); + + }); }); From 96244ad55c0ae09fe12e651bb706d7cb0cbb83a5 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 15:47:45 +0200 Subject: [PATCH 316/593] Implement stripUnit with quantity. Oops fdescribe. --- src/scripts/core.js | 6 +----- test/spec/spec-core.js | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index fe12b062..cae56021 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -79,11 +79,7 @@ var Chartist = { * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel */ Chartist.stripUnit = function(value) { - if(typeof value === 'string') { - value = value.replace(/[^0-9\+-\.]/g, ''); - } - - return +value; + return Chartist.quantity(value).value; }; /** diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 5f3b06e5..2f26b4c6 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -280,7 +280,7 @@ describe('Chartist core', function() { }); }); - fdescribe('quantity', function() { + describe('quantity', function() { it('should return value for numbers', function() { expect(Chartist.quantity(100)).toEqual({ value: 100 }); From 155bbac3aac60da6c69ee7edb4f65f8052e48bfe Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 16:18:46 +0200 Subject: [PATCH 317/593] Implement relative donutWidth. --- src/scripts/charts/pie.js | 10 +++++-- test/spec/spec-pie-chart.js | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 25ceae7b..dbd83437 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -35,6 +35,7 @@ // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. donut: 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, // If a label should be shown or not showLabel: true, @@ -98,10 +99,15 @@ return previousValue + currentValue; }, 0); + var donutWidth = Chartist.quantity(options.donutWidth); + if (donutWidth.unit === '%') { + donutWidth.value *= radius / 100; + } + // 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 ? options.donutWidth / 2 : 0; + radius -= options.donut ? 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 @@ -186,7 +192,7 @@ // If this is a donut, we add the stroke-width as style attribute if(options.donut) { pathElement.attr({ - 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' + 'style': 'stroke-width: ' + (donutWidth.value) + 'px' }); } diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 2cb7602a..ecac8fe4 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -182,4 +182,59 @@ describe('Pie chart tests', function() { }); }); + + describe('Pie Chart with relative donutWidth', function() { + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var data = { + series: [20, 10, 30, 40] + }; + var options = { + chartPadding:50, + height:500, + width:500, + donut: true, + donutWidth: '25%', + showLabel: false + }; + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('should render four strokes', function(done) { + onCreated(function() { + expect($('.ct-slice-donut').length).toBe(4); + done(); + }); + }); + + it('should create slice path', function(done) { + onCreated(function() { + $('.ct-slice-donut').each(function() { + + var num = '\\d+(\\.\\d*)?'; + var pattern = + '^M' + num + ',' + num + + 'A175,175,0,0,0,' + num + ',' + num + + '$' + ; + var path = $(this).attr('d'); + expect(path).toMatch(pattern); + }); + done(); + }); + }) + + it('should set stroke-width', function(done) { + onCreated(function() { + $('.ct-slice-donut').each(function() { + var style = $(this).attr('style'); + expect(style).toMatch('stroke-width:\\s?50px'); + }); + done(); + }); + }); + }); + }); From ac9cd89588295fbd2ab84a9247d3a604e74a8ffd Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 16:27:08 +0200 Subject: [PATCH 318/593] Undo change of gauge-chart example id. --- site/data/pages/examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 6decec43..8e207f65 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -243,7 +243,7 @@ sections: data: title: Gauge chart level: 4 - id: gauge-chart + id: simple-gauge-chart classes: ct-golden-section ct-negative-labels intro: This pie chart uses donut, startAngle and total to draw a gauge chart. From f4a1ef8fb4ead151f696effe8b13808f82ef3edf Mon Sep 17 00:00:00 2001 From: hansmaad Date: Tue, 29 Sep 2015 17:24:11 +0200 Subject: [PATCH 319/593] Replace calls to stripUnit with quantity. --- src/scripts/core.js | 8 ++++---- src/scripts/svg.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index cae56021..4adf9fe6 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -103,7 +103,7 @@ var Chartist = { * * @memberof Chartist.Core * @param {String|Number} input - * @return {Object} Returns an object containing the value and the unit. + * @return {Object} Returns an object containing the value as number and the unit as string. */ Chartist.quantity = function(input) { if (typeof input === 'string') { @@ -456,7 +456,7 @@ var Chartist = { * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0); + return Math.max((Chartist.quantity(options.height).value || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0); }; /** @@ -736,8 +736,8 @@ var Chartist = { var yAxisOffset = hasAxis ? options.axisY.offset : 0; var xAxisOffset = hasAxis ? options.axisX.offset : 0; // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 - var width = svg.width() || Chartist.stripUnit(options.width) || 0; - var height = svg.height() || Chartist.stripUnit(options.height) || 0; + var width = svg.width() || Chartist.quantity(options.width).value || 0; + var height = svg.height() || Chartist.quantity(options.height).value || 0; var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 96c949cc..c31a67b0 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -433,7 +433,7 @@ // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin // which needs to be in ms aside - timeout = Chartist.stripUnit(animationDefinition.begin || 0); + timeout = Chartist.quantity(animationDefinition.begin || 0).value; animationDefinition.begin = 'indefinite'; } From c31146debf10dfeaa3dcbb214bc31038f8586462 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Wed, 30 Sep 2015 10:34:59 +0200 Subject: [PATCH 320/593] Add zoom plugin to documentation site. --- bower.json | 1 + site/data/pages/plugins.yml | 25 +++++++++++++++++ site/examples/example-plugin-zoom.js | 40 ++++++++++++++++++++++++++++ site/layouts/default.hbs | 1 + site/styles/_example-charts.scss | 6 +++++ 5 files changed, 73 insertions(+) create mode 100644 site/examples/example-plugin-zoom.js diff --git a/bower.json b/bower.json index ca58e17c..97c5e025 100755 --- a/bower.json +++ b/bower.json @@ -18,6 +18,7 @@ "chartist-plugin-axistitle": "~0.0.1", "chartist-plugin-threshold": "~0.0.1", "chartist-plugin-fill-donut": "~0.0.1", + "chartist-plugin-zoom": "~0.0.1", "matchMedia": "~0.2.0" }, "ignore": [ diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 20359aa8..8d144777 100755 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -254,6 +254,31 @@ sections: - - 'Link:' - 'chartist-plugin-threshold' + - type: sub-section + data: + title: Zoom Plugin + level: 4 + items: + - type: text + data: + text: > + The zoom plugin allows you to zoom into charts. + - type: live-example + data: + id: example-plugin-zoom + classes: ct-golden-section + intro: > + Use the left mouse button to drag a zoom box. The plugin provides a callback that can be used to reset the zoom. + - type: table + data: + rows: + - + - 'Author:' + - Hannes Kamecke + - + - 'Link:' + - 'chartist-plugin-zoom' + - title: Develop a plugin level: 3 items: diff --git a/site/examples/example-plugin-zoom.js b/site/examples/example-plugin-zoom.js new file mode 100644 index 00000000..7bdbed8d --- /dev/null +++ b/site/examples/example-plugin-zoom.js @@ -0,0 +1,40 @@ +var data = { + series: [[ + { x: 1, y: 100 }, + { x: 2, y: 50 }, + { x: 3, y: 25 }, + { x: 4, y: 66 }, + { x: 5, y: 30 }, + { x: 6, y: 22 }, + ]] +}; + +var options = { + axisX: { + type: Chartist.AutoScaleAxis + }, + axisY: { + type: Chartist.AutoScaleAxis + }, + plugins: [ + Chartist.plugins.zoom({ onZoom: onZoom }) + ] +}; + +var chart = Chartist.Line('.ct-chart', data, options); +var resetFnc; +function onZoom(chart, reset) { + resetFnc = reset; +} + + +var btn = document.createElement('button'); +btn.id = 'reset-zoom-btn' +btn.innerHTML = 'Reset Zoom'; +btn.style.float = 'right'; +btn.addEventListener('click', function() { + console.log(resetFnc); + resetFnc && resetFnc(); +}); +var parent = document.querySelector('#example-plugin-zoom .chart'); +!parent.querySelector('#reset-zoom-btn') && parent.appendChild(btn); diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 449b475c..f919a6ba 100755 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -76,6 +76,7 @@ + diff --git a/site/styles/_example-charts.scss b/site/styles/_example-charts.scss index 4b36ea64..685d6362 100755 --- a/site/styles/_example-charts.scss +++ b/site/styles/_example-charts.scss @@ -108,3 +108,9 @@ } } +#example-plugin-zoom { + .ct-zoom-rect { + fill: rgba(200, 100, 100, 0.3); + stroke: red; + } +} From 20f1d9a42b59fe6c2ff9a78c95e753be139c6252 Mon Sep 17 00:00:00 2001 From: Douglas Mak Date: Wed, 30 Sep 2015 20:19:21 +0900 Subject: [PATCH 321/593] Reversed the stackMode options names --- src/scripts/charts/bar.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 7168a9a4..fc3104b7 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -78,9 +78,9 @@ seriesBarDistance: 15, // If set to true this property will cause the series bars to be stacked. The default stack mode is `accumulate`. stackBars: false, - // If set to 'accumulate' this property will force the stacked bars to draw from the zero line. - // If set to 'overlap' 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. - stackMode: 'overlap', + // If set to 'overlap' this property will force the stacked bars to draw from the zero line. + // 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. + stackMode: 'accumulate', // 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. horizontalBars: false, // 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. @@ -324,16 +324,16 @@ positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; - if(options.stackBars && options.stackMode == 'overlap') { - // Stack mode: overlap (default) + if(options.stackBars && (options.stackMode == 'accumulate' || !options.stackMode)) { + // Stack mode: accumulate (default) // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line // We want backwards compatibility, so the expected fallback without the 'stackMode' option - // should be the original (overlap) + // to be the original behaviour (accumulate) positions[labelAxis.counterUnits.pos + '1'] = previousStack; positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; } else { // Draw from the zero line normally - // This is also the same code for Stack mode: accumulate + // This is also the same code for Stack mode: overlap positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; } From 690f3293849f3233106fb4dc581943c6916cfa23 Mon Sep 17 00:00:00 2001 From: Douglas Mak Date: Wed, 30 Sep 2015 21:56:34 +0900 Subject: [PATCH 322/593] Replaced equality check with a strict equal --- src/scripts/charts/bar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index fc3104b7..0c986ac7 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -324,7 +324,7 @@ positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; - if(options.stackBars && (options.stackMode == 'accumulate' || !options.stackMode)) { + if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) { // Stack mode: accumulate (default) // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line // We want backwards compatibility, so the expected fallback without the 'stackMode' option From f37ffbb35ae5b3a1362cd10c1647c261b1de1e33 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Wed, 30 Sep 2015 15:29:37 +0200 Subject: [PATCH 323/593] Remove unnecessary parens in Pie.createChart --- src/scripts/charts/pie.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index dbd83437..600d84ee 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -192,7 +192,7 @@ // If this is a donut, we add the stroke-width as style attribute if(options.donut) { pathElement.attr({ - 'style': 'stroke-width: ' + (donutWidth.value) + 'px' + 'style': 'stroke-width: ' + donutWidth.value + 'px' }); } From 126a78c35ccbaf6bdd035b221a423fb6a81a03b5 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Wed, 30 Sep 2015 15:37:14 +0200 Subject: [PATCH 324/593] Remove stripUnit function from core. --- src/scripts/core.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 4adf9fe6..3bbd523b 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -71,17 +71,6 @@ var Chartist = { return str.replace(new RegExp(subStr, 'g'), newSubStr); }; - /** - * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {String|Number} value - * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel - */ - Chartist.stripUnit = function(value) { - return Chartist.quantity(value).value; - }; - /** * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. * From 863c0bfc994cee1dff823d11c631052b96281571 Mon Sep 17 00:00:00 2001 From: Adarsh Pandit Date: Wed, 30 Sep 2015 10:56:11 -0700 Subject: [PATCH 325/593] Add Plugin links to the README.md Reason for change: * The plugin ecosystem, while awesome, isn't easy to find Change: * Add a section to the `README.md` file to show some example plugins. * Also add a link to the beautiful web documentation site, which assumedly is probably most up-to-date going forward. --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index fcbeba69..9dcf99c5 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,20 @@ to the masses. 5. Richer Sass / CSS framework 6. Other charts types (spider etc.) +## Plugins + +Some features aren't right for the core product +but there is a great set of plugins available +which add features like: + +* [Axis labels](http://gionkunz.github.io/chartist-js/plugins.html#axis-title-plugin) +* [Tooltips at data points](https://gionkunz.github.io/chartist-js/plugins.html#tooltip-plugin) +* [Coloring above/below a threshold](https://gionkunz.github.io/chartist-js/plugins.html#threshold-plugin) + +and more. + +See all the plugins [here](https://gionkunz.github.io/chartist-js/plugins.html). + ## Contribution We are looking for people who share the idea of having a simple, flexible charting library that is responsive and uses From 3e237444754f6d6974c38e8ef9ab0adff10ae287 Mon Sep 17 00:00:00 2001 From: Martin Ciparelli Date: Thu, 5 Nov 2015 20:35:26 -0300 Subject: [PATCH 326/593] added style to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 7771c528..e93fa7fd 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "package.json", "README.md" ], + "style": "dist/chartist.min.css", "main": "dist/chartist.js", "browser": "dist/chartist.js", "licenses": [ From 5d8dc955324f02047a1088e61e31f8c67dedf504 Mon Sep 17 00:00:00 2001 From: medzes Date: Mon, 9 Nov 2015 22:04:35 +0100 Subject: [PATCH 327/593] Small fix for stacked bars with 'holes' in the data --- src/scripts/charts/bar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 0c986ac7..d90c01f7 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -138,8 +138,8 @@ return value; }).reduce(function(prev, curr) { return { - x: prev.x + curr.x || 0, - y: prev.y + curr.y || 0 + x: prev.x + (curr && curr.x) || 0, + y: prev.y + (curr && curr.y) || 0 }; }, {x: 0, y: 0}); }); From d10944ae74eaf95880b411a8c768f1002ceb7dba Mon Sep 17 00:00:00 2001 From: Carlos Morales Date: Sat, 14 Nov 2015 16:15:13 +0100 Subject: [PATCH 328/593] fix jshint errors on spec-pie-chart.js --- test/spec/spec-pie-chart.js | 115 ++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index ecac8fe4..4968e567 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -33,10 +33,10 @@ describe('Pie chart tests', function() { }); }); }); - + describe('Simple Pie Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#simple-pie-chart - + function onCreated(callback) { jasmine.getFixtures().set('
    '); var data = { @@ -51,46 +51,45 @@ describe('Pie chart tests', function() { } }; - var sum = function(a, b) { return a + b }; + var sum = function(a, b) { return a + b; }; var chart = new Chartist.Pie('.ct-chart', data, options); chart.on('created', callback); } - + it('should render three slices', function(done) { onCreated(function() { expect($('.ct-slice-pie').length).toBe(3); done(); }); }); - + it('should set value attribute', function(done) { onCreated(function() { - var slices = $('.ct-slice-pie'); + var slices = $('.ct-slice-pie'); expect(slices.eq(2).attr('ct:value')).toBe('5'); expect(slices.eq(1).attr('ct:value')).toBe('3'); expect(slices.eq(0).attr('ct:value')).toBe('4'); done(); - }); + }); }); - + it('should create slice path', function(done) { onCreated(function() { $('.ct-slice-pie').each(function() { - + var num = '\\d+(\\.\\d*)?'; - var pattern = - '^M' + num + ',' + num - + 'A40,40,0,0,0,' + num + ',' + num - + 'L50,50Z$' - ; + var pattern = + '^M' + num + ',' + num + + 'A40,40,0,0,0,' + num + ',' + num + + 'L50,50Z$'; var path = $(this).attr('d'); expect(path).toMatch(pattern); }); done(); - }); - }) - + }); + }); + it('should add labels', function(done) { onCreated(function() { var labels = $('.ct-label'); @@ -99,15 +98,15 @@ describe('Pie chart tests', function() { expect(labels.eq(2).text()).toBe('33%'); done(); }); - - }); + + }); }); - - - + + + describe('Gauge Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#gauge-chart - + function onCreated(callback) { jasmine.getFixtures().set('
    '); var data = { @@ -126,65 +125,64 @@ describe('Pie chart tests', function() { var chart = new Chartist.Pie('.ct-chart', data, options); chart.on('created', callback); } - + it('should render four strokes', function(done) { onCreated(function() { expect($('.ct-slice-donut').length).toBe(4); done(); }); }); - + it('should set value attribute', function(done) { onCreated(function() { var slices = $('.ct-slice-donut'); - expect(slices.eq(3).attr('ct:value')).toBe('20'); + expect(slices.eq(3).attr('ct:value')).toBe('20'); expect(slices.eq(2).attr('ct:value')).toBe('10'); expect(slices.eq(1).attr('ct:value')).toBe('30'); expect(slices.eq(0).attr('ct:value')).toBe('40'); done(); - }); + }); }); - + it('should create slice path', function(done) { onCreated(function() { $('.ct-slice-donut').each(function() { - + var num = '\\d+(\\.\\d*)?'; - var pattern = - '^M' + num + ',' + num - + 'A170,170,0,0,0,' + num + ',' + num - + '$' - ; + var pattern = + '^M' + num + ',' + num + + 'A170,170,0,0,0,' + num + ',' + num + + '$'; var path = $(this).attr('d'); expect(path).toMatch(pattern); }); done(); - }); - }) - + }); + }); + it('should set stroke-width', function(done) { onCreated(function() { - $('.ct-slice-donut').each(function() { + $('.ct-slice-donut').each(function() { var style = $(this).attr('style'); expect(style).toMatch('stroke-width:\\s?60px'); }); done(); - }); + }); }); - + it('should not add labels', function(done) { onCreated(function() { var labels = $('.ct-label'); - expect(labels.length).toBe(0); + expect(labels.length).toBe(0); done(); }); - + }); - + }); - + describe('Pie Chart with relative donutWidth', function() { - + function onCreated(callback) { jasmine.getFixtures().set('
    '); var data = { @@ -201,7 +199,7 @@ describe('Pie chart tests', function() { var chart = new Chartist.Pie('.ct-chart', data, options); chart.on('created', callback); } - + it('should render four strokes', function(done) { onCreated(function() { expect($('.ct-slice-donut').length).toBe(4); @@ -212,29 +210,28 @@ describe('Pie chart tests', function() { it('should create slice path', function(done) { onCreated(function() { $('.ct-slice-donut').each(function() { - + var num = '\\d+(\\.\\d*)?'; - var pattern = - '^M' + num + ',' + num - + 'A175,175,0,0,0,' + num + ',' + num - + '$' - ; + var pattern = + '^M' + num + ',' + num + + 'A175,175,0,0,0,' + num + ',' + num + + '$'; var path = $(this).attr('d'); expect(path).toMatch(pattern); }); done(); - }); - }) - + }); + }); + it('should set stroke-width', function(done) { onCreated(function() { - $('.ct-slice-donut').each(function() { + $('.ct-slice-donut').each(function() { var style = $(this).attr('style'); expect(style).toMatch('stroke-width:\\s?50px'); }); done(); - }); - }); + }); + }); }); - + }); From 26cbdeccaf78b0d987c46bd674f2313ced54d279 Mon Sep 17 00:00:00 2001 From: Carlos Morales Date: Sat, 14 Nov 2015 16:51:52 +0100 Subject: [PATCH 329/593] fixes #411: Order scale axis tick --- src/scripts/axes/fixed-scale-axis.js | 3 ++ test/spec/spec-axes.js | 53 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 test/spec/spec-axes.js diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index b56112f9..bb42f9cc 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -27,6 +27,9 @@ this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return highLow.low + (highLow.high - highLow.low) / this.divisor * index; }.bind(this)); + this.ticks.sort(function(a, b) { + return a - b; + }); this.range = { min: highLow.low, max: highLow.high diff --git a/test/spec/spec-axes.js b/test/spec/spec-axes.js new file mode 100644 index 00000000..4eadbdc4 --- /dev/null +++ b/test/spec/spec-axes.js @@ -0,0 +1,53 @@ +describe('Axes tests', function() { + 'use strict'; + + beforeEach(function() { + + }); + + afterEach(function() { + + }); + + describe('fixed scale axis', function () { + it('should order the tick array', function() { + + var ticks = [10, 5, 0, -5, -10], + axisUnit = { + 'pos':'y', + 'len':'height', + 'dir':'vertical', + 'rectStart':'y2', + 'rectEnd':'y1', + 'rectOffset':'x1' + }, + data = { + 'raw': { + 'series':[[ {x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5} ]] + }, + 'normalized':[[ {'y':10,'x':1},{'y':5,'x':2},{'y':-5,'x':3} ]] + }, + chartRect = { + 'padding':{'top':15,'right':15,'bottom':5,'left':10}, + 'y2':15, + 'y1':141, + 'x1':50, + 'x2':269 + }, + options = { + 'offset':40, + 'position':'start', + 'labelOffset':{'x':0,'y':0}, + 'showLabel':true, + 'showGrid':true, + 'scaleMinSpace':20, + 'onlyInteger':false, + 'ticks': ticks + }, + fsaxis = new Chartist.FixedScaleAxis(axisUnit, data, chartRect, options); + expect(fsaxis.ticks).toEqual([-10, -5, 0, 5, 10]); + }); + + }); + +}); From 78d85e2d8f0340b1422c77b71d1d9d26284214fb Mon Sep 17 00:00:00 2001 From: Carlos Morales Date: Sat, 14 Nov 2015 17:23:04 +0100 Subject: [PATCH 330/593] fixes #514: left navigation in examples was not using valid anchors --- site/partials/side-navigation.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/partials/side-navigation.hbs b/site/partials/side-navigation.hbs index a6be4d7a..2ef200af 100644 --- a/site/partials/side-navigation.hbs +++ b/site/partials/side-navigation.hbs @@ -9,7 +9,7 @@ {{/is}} {{#is type 'live-example'}} -
  • {{data.title}}
  • +
  • {{data.title}}
  • {{/is}} {{/each}} {{/each}} From 484a8e8a670e4a51535ad12c454b1c7b0f7d6ae4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 14 Nov 2015 19:27:12 +0100 Subject: [PATCH 331/593] Minor formatting cleanup --- site/data/pages/plugins.yml | 3 +-- site/examples/example-plugin-zoom.js | 7 +++---- site/styles/_example-charts.scss | 8 ++++---- src/scripts/charts/bar.js | 12 ++++++------ src/scripts/charts/pie.js | 4 ++-- src/scripts/core.js | 4 ++-- src/scripts/interpolation.js | 8 ++++---- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 8d144777..ca8988d5 100755 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -277,8 +277,7 @@ sections: - Hannes Kamecke - - 'Link:' - - 'chartist-plugin-zoom' - + - 'chartist-plugin-zoom' - title: Develop a plugin level: 3 items: diff --git a/site/examples/example-plugin-zoom.js b/site/examples/example-plugin-zoom.js index 7bdbed8d..08668360 100644 --- a/site/examples/example-plugin-zoom.js +++ b/site/examples/example-plugin-zoom.js @@ -5,12 +5,12 @@ var data = { { x: 3, y: 25 }, { x: 4, y: 66 }, { x: 5, y: 30 }, - { x: 6, y: 22 }, + { x: 6, y: 22 } ]] }; var options = { - axisX: { + axisX: { type: Chartist.AutoScaleAxis }, axisY: { @@ -27,9 +27,8 @@ function onZoom(chart, reset) { resetFnc = reset; } - var btn = document.createElement('button'); -btn.id = 'reset-zoom-btn' +btn.id = 'reset-zoom-btn'; btn.innerHTML = 'Reset Zoom'; btn.style.float = 'right'; btn.addEventListener('click', function() { diff --git a/site/styles/_example-charts.scss b/site/styles/_example-charts.scss index 685d6362..16103e65 100755 --- a/site/styles/_example-charts.scss +++ b/site/styles/_example-charts.scss @@ -96,14 +96,14 @@ h3 { font-weight: bolder; } - + small { font-size: 0.6em; } - - i { - font-size: 1.5em; + + i { + font-size: 1.5em; } } diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 0c986ac7..d871497a 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -76,8 +76,8 @@ }, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, - // If set to true this property will cause the series bars to be stacked. The default stack mode is `accumulate`. - stackBars: false, + // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options. + stackBars: false, // If set to 'overlap' this property will force the stacked bars to draw from the zero line. // 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. stackMode: 'accumulate', @@ -323,19 +323,19 @@ var positions = {}; positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; - + if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) { // Stack mode: accumulate (default) // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - // We want backwards compatibility, so the expected fallback without the 'stackMode' option + // We want backwards compatibility, so the expected fallback without the 'stackMode' option // to be the original behaviour (accumulate) positions[labelAxis.counterUnits.pos + '1'] = previousStack; positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; - } else { + } else { // Draw from the zero line normally // This is also the same code for Stack mode: overlap positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; - positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; + positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; } // Limit x and y so that they are within the chart rect diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 600d84ee..56728183 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -35,7 +35,7 @@ // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. donut: 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%'). + // This option can be set as number or string to specify a relative width (i.e. 100 or '30%'). donutWidth: 60, // If a label should be shown or not showLabel: true, @@ -103,7 +103,7 @@ if (donutWidth.unit === '%') { donutWidth.value *= radius / 100; } - + // 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 diff --git a/src/scripts/core.js b/src/scripts/core.js index 3bbd523b..e7a70962 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -90,7 +90,7 @@ var Chartist = { /** * Converts a number or string to a quantity object. * - * @memberof Chartist.Core + * @memberof Chartist.Core * @param {String|Number} input * @return {Object} Returns an object containing the value as number and the unit as string. */ @@ -700,7 +700,7 @@ var Chartist = { * @param {Number} centerY X-axis coordinates of center point of circle segment * @param {Number} radius Radius of circle segment * @param {Number} angleInDegrees Angle of circle segment in degrees - * @return {Number} Coordinates of point on circumference + * @return {{x:Number, y:Number}} Coordinates of point on circumference */ Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index e122a47d..8058d941 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -28,7 +28,7 @@ */ Chartist.Interpolation.none = function(options) { var defaultOptions = { - fillHoles: false, + fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); return function none(pathCoordinates, valueData) { @@ -84,7 +84,7 @@ Chartist.Interpolation.simple = function(options) { var defaultOptions = { divisor: 2, - fillHoles: false, + fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); @@ -154,7 +154,7 @@ Chartist.Interpolation.cardinal = function(options) { var defaultOptions = { tension: 1, - fillHoles: false, + fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); @@ -288,7 +288,7 @@ Chartist.Interpolation.step = function(options) { var defaultOptions = { postpone: true, - fillHoles: false, + fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); From 6f0dc1a38065aab546a8c11d8d1ccc5087fa1325 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 14 Nov 2015 19:48:27 +0100 Subject: [PATCH 332/593] Removed tooltip examples as people should use the tooltip plugin --- site/data/pages/examples.yml | 10 ------- site/data/pages/getting-started.yml | 24 ----------------- site/examples/behavior-with-jquery.js | 38 --------------------------- site/styles/_example-charts.scss | 6 ----- site/styles/main.scss | 25 ------------------ 5 files changed, 103 deletions(-) delete mode 100644 site/examples/behavior-with-jquery.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 8e207f65..e0084c29 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -48,16 +48,6 @@ sections: This advanced example uses a line chart to draw a scatter diagram. The data object is created with a functional style random mechanism. There is a mobile first responsive configuration using the responsive options to show less labels on small screens. - - type: live-example - data: - title: Line chart with tooltips - level: 4 - id: behavior-with-jquery - classes: ct-golden-section - intro: > - Adding behavior to your chart with JavaScript is a breeze and is just like any other DOM manipulation - you do to your site. This is just one of many benefits of using inline-SVG and provides you with the - freedom you need in order to create exactly the experience you're looking for. - type: live-example data: title: Line chart with area diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 1fedee37..48071abe 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -576,30 +576,6 @@ sections: to implement certain things yourself. This topic should cover some of these use-cases and give you some basic idea why and how to implement certain functionality. - - type: sub-section - data: - title: Adding behaviour to your charts - level: 4 - items: - - type: text - data: - text: > - This example shows you how you can easily build a tool tip on top of Chartist using jQuery and some - basic styling. It makes use of the ct-series-name and ct-value custom attributes that are present - on all SVG elements generated by Chartist. - - type: text - data: - text: > - We actually do a few things here that would go against a proper style guide (like animating with - JavaScript and changing styles instead of switching classes etc.), but this example is only for - illustrating how easy behavior could be attached to Chartist. - - - type: example-chart - data: - id: behavior-with-jquery - classes: ct-golden-section - show-code-button: Show code - - type: sub-section data: title: Animations using Chartist.Svg diff --git a/site/examples/behavior-with-jquery.js b/site/examples/behavior-with-jquery.js deleted file mode 100644 index b9c77adf..00000000 --- a/site/examples/behavior-with-jquery.js +++ /dev/null @@ -1,38 +0,0 @@ -new Chartist.Line('.ct-chart', { - labels: ['1', '2', '3', '4', '5', '6'], - series: [ - { - name: 'Fibonacci sequence', - data: [1, 2, 3, 5, 8, 13] - }, - { - name: 'Golden section', - data: [1, 1.618, 2.618, 4.236, 6.854, 11.09] - } - ] -}); - -var $chart = $('.ct-chart'); - -var $toolTip = $chart - .append('
    ') - .find('.tooltip') - .hide(); - -$chart.on('mouseenter', '.ct-point', function() { - var $point = $(this), - value = $point.attr('ct:value'), - seriesName = $point.parent().attr('ct:series-name'); - $toolTip.html(seriesName + '
    ' + value).show(); -}); - -$chart.on('mouseleave', '.ct-point', function() { - $toolTip.hide(); -}); - -$chart.on('mousemove', function(event) { - $toolTip.css({ - left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, - top: (event.offsetY || event.originalEvent.layerY) - $toolTip.height() - 40 - }); -}); diff --git a/site/styles/_example-charts.scss b/site/styles/_example-charts.scss index 16103e65..f65cd26c 100755 --- a/site/styles/_example-charts.scss +++ b/site/styles/_example-charts.scss @@ -48,12 +48,6 @@ } } -#behavior-with-jquery { - .ct-point { - @include ct-chart-point($ct-point-size: 20px); - } -} - #example-plugin-threshold { .ct-line { stroke-dasharray: 5px; diff --git a/site/styles/main.scss b/site/styles/main.scss index 8d26eba6..9e617c52 100644 --- a/site/styles/main.scss +++ b/site/styles/main.scss @@ -76,31 +76,6 @@ } } -.tooltip { - position: absolute; - display: inline-block; - min-width: 5em; - padding: 0.5em; - background: $color-yellow; - color: $color-black; - font-weight: 700; - text-align: center; - pointer-events: none; - z-index: 1; - - &:after { - content: ""; - position: absolute; - top: 100%; - left: 50%; - width: 0; - height: 0; - margin-left: -15px; - border: 15px solid transparent; - border-top-color: $color-yellow; - } -} - code { font-family: "Source Code Pro", "Courier New", monospace !important; word-wrap: break-word; From 62ff24753aaf82577c52464a493a97d5ed079159 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 14 Nov 2015 19:49:11 +0100 Subject: [PATCH 333/593] Updated grunt imagemin --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e93fa7fd..246d43f6 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "grunt-contrib-copy": "^0.7.0", "grunt-contrib-cssmin": "^0.12.1", "grunt-contrib-htmlmin": "~0.4.0", - "grunt-contrib-imagemin": "~0.9.3", + "grunt-contrib-imagemin": "^1.0.0", "grunt-contrib-jasmine": "~0.8.2", "grunt-contrib-jshint": "~0.11.0", "grunt-contrib-uglify": "^0.7.0", From 4d2ef6f48cc87af75c6167bdc11ba8083bfc7e6e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 14 Nov 2015 19:49:58 +0100 Subject: [PATCH 334/593] Version bump to 0.9.5 --- CHANGELOG.md | 9 ++ dist/chartist.js | 204 +++++++++++++++++++++++---------------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 6 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- 6 files changed, 138 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efb142d6..6c92cc31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +v0.9.5 - 14 Nov 2015 +-------------------- +- Added 'fillHoles' option for line graphs, which continues the line smoothly through data holes (Thanks to Joshua Warner !) +- Added option to use relative donut width values (Thanks to hansmaad !) +- Added stackMode for bar charts to create overlapping charts or bipolar stacked charts (Thanks to Douglas Mak !) +- Fixed issue with unordered ticks in fixed scale axis, fixes #411 (Thanks Carlos !) +- Fixed left navigation in examples was not using valid anchors, fixes #514 (Thanks Carlos !) +- Internal refactoring and cleanup (Thanks to hansmaad !) + v0.9.4 - 06 Aug 2015 -------------------- - Added axes to all events where they are available in context to provide better API convenience when developing plugins diff --git a/dist/chartist.js b/dist/chartist.js index 5c5b9310..5588129e 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.4 +/* Chartist.js 0.9.5 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ @@ -25,7 +25,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.4' + version: '0.9.5' }; (function (window, document, Chartist) { @@ -92,21 +92,6 @@ var Chartist = { return str.replace(new RegExp(subStr, 'g'), newSubStr); }; - /** - * Converts a string to a number while removing the unit if present. If a number is passed then this will be returned unmodified. - * - * @memberof Chartist.Core - * @param {String|Number} value - * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel - */ - Chartist.stripUnit = function(value) { - if(typeof value === 'string') { - value = value.replace(/[^0-9\+-\.]/g, ''); - } - - return +value; - }; - /** * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. * @@ -123,6 +108,24 @@ var Chartist = { return value; }; + /** + * Converts a number or string to a quantity object. + * + * @memberof Chartist.Core + * @param {String|Number} input + * @return {Object} Returns an object containing the value as number and the unit as string. + */ + Chartist.quantity = function(input) { + if (typeof input === 'string') { + var match = (/^(\d+)\s*(.*)$/g).exec(input); + return { + value : +match[1], + unit: match[2] || undefined + }; + } + return { value: input }; + }; + /** * This is a wrapper around document.querySelector that will return the query if it's already of type Node * @@ -463,7 +466,7 @@ var Chartist = { * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { - return Math.max((Chartist.stripUnit(options.height) || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0); + return Math.max((Chartist.quantity(options.height).value || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0); }; /** @@ -718,7 +721,7 @@ var Chartist = { * @param {Number} centerY X-axis coordinates of center point of circle segment * @param {Number} radius Radius of circle segment * @param {Number} angleInDegrees Angle of circle segment in degrees - * @return {Number} Coordinates of point on circumference + * @return {{x:Number, y:Number}} Coordinates of point on circumference */ Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; @@ -743,8 +746,8 @@ var Chartist = { var yAxisOffset = hasAxis ? options.axisY.offset : 0; var xAxisOffset = hasAxis ? options.axisX.offset : 0; // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 - var width = svg.width() || Chartist.stripUnit(options.width) || 0; - var height = svg.height() || Chartist.stripUnit(options.height) || 0; + var width = svg.width() || Chartist.quantity(options.width).value || 0; + var height = svg.height() || Chartist.quantity(options.height).value || 0; var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust @@ -967,30 +970,45 @@ var Chartist = { /** * This interpolation function does not smooth the path and the result is only containing lines and no curves. * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.none({ + * fillHoles: false + * }) + * }); + * + * * @memberof Chartist.Interpolation * @return {Function} */ - Chartist.Interpolation.none = function() { + Chartist.Interpolation.none = function(options) { + var defaultOptions = { + fillHoles: false + }; + options = Chartist.extend({}, defaultOptions, options); return function none(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); - // We need to assume that the first value is a "hole" var hole = true; - for(var i = 1; i < pathCoordinates.length; i += 2) { - var data = valueData[(i - 1) / 2]; + for(var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var currData = valueData[i / 2]; + + if(currData.value !== undefined) { - // If the current value is undefined we should treat it as a hole start - if(data.value === undefined) { - hole = true; - } else { - // If this value is valid we need to check if we're coming out of a hole if(hole) { - // If we are coming out of a hole we should first make a move and also reset the hole flag - path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data); - hole = false; + path.move(currX, currY, false, currData); } else { - path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data); + path.line(currX, currY, false, currData); } + + hole = false; + } else if(!options.fillHoles) { + hole = true; } } @@ -1011,7 +1029,8 @@ var Chartist = { * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.simple({ - * divisor: 2 + * divisor: 2, + * fillHoles: false * }) * }); * @@ -1022,7 +1041,8 @@ var Chartist = { */ Chartist.Interpolation.simple = function(options) { var defaultOptions = { - divisor: 2 + divisor: 2, + fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); @@ -1030,26 +1050,19 @@ var Chartist = { return function simple(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); - var hole = true; + var prevX, prevY, prevData; - for(var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2]; - var prevY = pathCoordinates[i - 1]; + for(var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; var currY = pathCoordinates[i + 1]; var length = (currX - prevX) * d; - var prevData = valueData[(i / 2) - 1]; var currData = valueData[i / 2]; - if(prevData.value === undefined) { - hole = true; - } else { + if(currData.value !== undefined) { - if(hole) { - path.move(prevX, prevY, false, prevData); - } - - if(currData.value !== undefined) { + if(prevData === undefined) { + path.move(currX, currY, false, currData); + } else { path.curve( prevX + length, prevY, @@ -1060,9 +1073,13 @@ var Chartist = { false, currData ); - - hole = false; } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if(!options.fillHoles) { + prevX = currX = prevData = undefined; } } @@ -1083,7 +1100,8 @@ var Chartist = { * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.cardinal({ - * tension: 1 + * tension: 1, + * fillHoles: false * }) * }); * @@ -1093,7 +1111,8 @@ var Chartist = { */ Chartist.Interpolation.cardinal = function(options) { var defaultOptions = { - tension: 1 + tension: 1, + fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); @@ -1111,7 +1130,9 @@ var Chartist = { for(var i = 0; i < pathCoordinates.length; i += 2) { // If this value is a "hole" we set the hole flag if(valueData[i / 2].value === undefined) { - hole = true; + if(!options.fillHoles) { + hole = true; + } } else { // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment if(hole) { @@ -1213,7 +1234,8 @@ var Chartist = { * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.step({ - * postpone: true + * postpone: true, + * fillHoles: false * }) * }); * @@ -1223,34 +1245,27 @@ var Chartist = { */ Chartist.Interpolation.step = function(options) { var defaultOptions = { - postpone: true + postpone: true, + fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); return function step(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); - var hole = true; - for (var i = 2; i < pathCoordinates.length; i += 2) { - var prevX = pathCoordinates[i - 2]; - var prevY = pathCoordinates[i - 1]; + var prevX, prevY, prevData; + + for (var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; var currY = pathCoordinates[i + 1]; - var prevData = valueData[(i / 2) - 1]; var currData = valueData[i / 2]; - // If last point is a "hole" - if(prevData.value === undefined) { - hole = true; - } else { - // If last point is not a "hole" but we just came back out of a "hole" we need to move first - if(hole) { - path.move(prevX, prevY, false, prevData); - } - - // If the current point is also not a hole we can draw the step lines - if(currData.value !== undefined) { + // If the current point is also not a hole we can draw the step lines + if(currData.value !== undefined) { + if(prevData === undefined) { + path.move(currX, currY, false, currData); + } else { if(options.postpone) { // If postponed we should draw the step line with the value of the previous value path.line(currX, prevY, false, prevData); @@ -1260,9 +1275,13 @@ var Chartist = { } // Line to the actual point (this should only be a Y-Axis movement path.line(currX, currY, false, currData); - // Reset the "hole" flag as previous and current point have valid values - hole = false; } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if(!options.fillHoles) { + prevX = prevY = prevData = undefined; } } @@ -2084,7 +2103,7 @@ var Chartist = { // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin // which needs to be in ms aside - timeout = Chartist.stripUnit(animationDefinition.begin || 0); + timeout = Chartist.quantity(animationDefinition.begin || 0).value; animationDefinition.begin = 'indefinite'; } @@ -2844,6 +2863,9 @@ var Chartist = { this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return highLow.low + (highLow.high - highLow.low) / this.divisor * index; }.bind(this)); + this.ticks.sort(function(a, b) { + return a - b; + }); this.range = { min: highLow.low, max: highLow.high @@ -3399,8 +3421,11 @@ var Chartist = { }, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, - // If set to true this property will cause the series bars to be stacked and 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. + // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options. stackBars: false, + // If set to 'overlap' this property will force the stacked bars to draw from the zero line. + // 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. + stackMode: 'accumulate', // 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. horizontalBars: false, // 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. @@ -3643,9 +3668,20 @@ var Chartist = { var positions = {}; positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; - // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line - positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint; - positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos]; + + if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) { + // Stack mode: accumulate (default) + // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line + // We want backwards compatibility, so the expected fallback without the 'stackMode' option + // to be the original behaviour (accumulate) + positions[labelAxis.counterUnits.pos + '1'] = previousStack; + positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; + } else { + // Draw from the zero line normally + // This is also the same code for Stack mode: overlap + positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; + } // Limit x and y so that they are within the chart rect positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); @@ -3777,6 +3813,7 @@ var Chartist = { // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. donut: 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, // If a label should be shown or not showLabel: true, @@ -3840,10 +3877,15 @@ var Chartist = { return previousValue + currentValue; }, 0); + var donutWidth = Chartist.quantity(options.donutWidth); + if (donutWidth.unit === '%') { + donutWidth.value *= radius / 100; + } + // 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 ? options.donutWidth / 2 : 0; + radius -= options.donut ? 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 @@ -3928,7 +3970,7 @@ var Chartist = { // If this is a donut, we add the stroke-width as style attribute if(options.donut) { pathElement.attr({ - 'style': 'stroke-width: ' + (+options.donutWidth) + 'px' + 'style': 'stroke-width: ' + donutWidth.value + 'px' }); } diff --git a/dist/chartist.min.css b/dist/chartist.min.css index f348f0ae..e1c280e5 100644 --- a/dist/chartist.min.css +++ b/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-double-octave:after,.ct-double-octave:before,.ct-golden-section:after,.ct-major-eleventh:after,.ct-major-eleventh:before,.ct-major-second:after,.ct-major-second:before,.ct-major-seventh:after,.ct-major-seventh:before,.ct-major-sixth:after,.ct-major-sixth:before,.ct-major-tenth:after,.ct-major-tenth:before,.ct-major-third:after,.ct-major-third:before,.ct-major-twelfth:after,.ct-major-twelfth:before,.ct-minor-second:after,.ct-minor-second:before,.ct-minor-seventh:after,.ct-minor-seventh:before,.ct-minor-sixth:after,.ct-minor-sixth:before,.ct-minor-third:after,.ct-minor-third:before,.ct-octave:after,.ct-octave:before,.ct-perfect-fifth:after,.ct-perfect-fifth:before,.ct-perfect-fourth:after,.ct-perfect-fourth:before,.ct-square:after,.ct-square:before{content:""}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.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-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{fill:none;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;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;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;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;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;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;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;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;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{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;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;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;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;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;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;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;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;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-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-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{fill:none;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 diff --git a/dist/chartist.min.js b/dist/chartist.min.js index b69e4846..dfb9e726 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,9 @@ -/* Chartist.js 0.9.4 +/* Chartist.js 0.9.5 * Copyright © 2015 Gion Kunz * Free to use under the WTFPL license. * http://www.wtfpl.net/ */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.4"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.stripUnit=function(a){return"string"==typeof a&&(a=a.replace(/[^0-9\+-\.]/g,"")),+a},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.stripUnit(b.width)||0,i=a.height()||c.stripUnit(b.height)||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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=2;g1}).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(h){var k=i.elem("path",{d:h.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:h.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:k})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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],v[l.counterUnits.pos+"1"]=a.stackBars?t:p,v[l.counterUnits.pos+"2"]=a.stackBars?q[k]:r[l.counterUnits.pos],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),s=h.elem("line",v,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri), -this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.reduce(function(a,b){return a+b},0),f-=a.donut?a.donutWidth/2:0,h="outside"===a.labelPosition||a.donut?f:"center"===a.labelPosition?0:f/2,h+=a.labelOffset;var m={x:e.x1+e.width()/2,y:e.y2+e.height()/2},n=1===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var o=0;o180,0,r.x,r.y);a.donut||t.line(m.x,m.y);var u=j[o].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(u.attr({value:l[o],meta:c.serialize(p.meta)},c.xmlNs.uri),a.donut&&u.attr({style:"stroke-width: "+ +a.donutWidth+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[o],totalDataSum:i,index:o,meta:p.meta,series:p,group:j[o],element:u,path:t.clone(),center:m,radius:f,startAngle:k,endAngle:q}),a.showLabel){var v=c.polarToCartesian(m.x,m.y,h,k+(q-k)/2),w=a.labelInterpolationFnc(this.data.labels?this.data.labels[o]:l[o],o);if(w||0===w){var x=b.elem("text",{dx:v.x,dy:v.y,"text-anchor":d(m,v,a.labelDirection)},a.classNames.label).text(""+w);this.eventEmitter.emit("draw",{type:"label",index:o,group:b,element:x,text:""+w,x:v.x,y:v.y})}}k=q}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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.5"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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(h){var k=i.elem("path",{d:h.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:h.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:k})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p180,0,s.x,s.y);a.donut||u.line(n.x,n.y);var v=j[p].elem("path",{d:u.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(v.attr({value:l[p],meta:c.serialize(q.meta)},c.xmlNs.uri),a.donut&&v.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:v,path:u.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var w=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),x=a.labelInterpolationFnc(this.data.labels?this.data.labels[p]:l[p],p);if(x||0===x){var y=b.elem("text",{dx:w.x,dy:w.y,"text-anchor":d(n,w,a.labelDirection)},a.classNames.label).text(""+x);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:y,text:""+x,x:w.x,y:w.y})}}k=r}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};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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 513c2720..2c87ca8c 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chartist.min.js","sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","stripUnit","value","ensureUnit","unit","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","undefined","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","pathCoordinates","valueData","path","Path","hole","move","line","simple","defaultOptions","d","prevX","prevY","currX","currY","prevData","currData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","match","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([], 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.9.4\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.4'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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 string to a number while removing the unit if present. If a number is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {String|Number} value\n * @return {Number} Returns the string as number or NaN if the passed length could not be converted to pixel\n */\n Chartist.stripUnit = function(value) {\n if(typeof value === 'string') {\n value = value.replace(/[^0-9\\+-\\.]/g, '');\n }\n\n return +value;\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 * 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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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.stripUnit(options.height) || 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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 {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.stripUnit(options.width) || 0;\n var height = svg.height() || Chartist.stripUnit(options.height) || 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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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 * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function() {\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n // We need to assume that the first value is a \"hole\"\n var hole = true;\n\n for(var i = 1; i < pathCoordinates.length; i += 2) {\n var data = valueData[(i - 1) / 2];\n\n // If the current value is undefined we should treat it as a hole start\n if(data.value === undefined) {\n hole = true;\n } else {\n // If this value is valid we need to check if we're coming out of a hole\n if(hole) {\n // If we are coming out of a hole we should first make a move and also reset the hole flag\n path.move(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n hole = false;\n } else {\n path.line(pathCoordinates[i - 1], pathCoordinates[i], false, data);\n }\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 * })\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 };\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 hole = true;\n\n for(var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n if(prevData.value === undefined) {\n hole = true;\n } else {\n\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n if(currData.value !== undefined) {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n\n hole = false;\n }\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 * })\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 };\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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n hole = true;\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 * })\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 };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for (var i = 2; i < pathCoordinates.length; i += 2) {\n var prevX = pathCoordinates[i - 2];\n var prevY = pathCoordinates[i - 1];\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var prevData = valueData[(i / 2) - 1];\n var currData = valueData[i / 2];\n\n // If last point is a \"hole\"\n if(prevData.value === undefined) {\n hole = true;\n } else {\n // If last point is not a \"hole\" but we just came back out of a \"hole\" we need to move first\n if(hole) {\n path.move(prevX, prevY, false, prevData);\n }\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\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 // Reset the \"hole\" flag as previous and current point have valid values\n hole = false;\n }\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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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.stripUnit(animationDefinition.begin || 0);\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 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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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.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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 and 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 stackBars: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n positions[labelAxis.counterUnits.pos + '1'] = options.stackBars ? previousStack : zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = options.stackBars ? stackedBarValues[valueIndex] : projected[labelAxis.counterUnits.pos];\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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\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.donutWidth / 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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: ' + (+options.donutWidth) + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","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([], 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.9.5\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.5'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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 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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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/package.json b/package.json index 246d43f6..a7705692 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.4", + "version": "0.9.5", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 0ac1a41f317f75e253b2566b35171f329141264e Mon Sep 17 00:00:00 2001 From: Alexandre Gigliotti Date: Wed, 18 Nov 2015 12:20:10 -0800 Subject: [PATCH 335/593] Add node-chartist to list of wrapper libraries. --- site/data/pages/index.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 2a61c4d8..a1ba21f3 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -216,6 +216,9 @@ sections: - Project - Type rows: + - + - 'node-chartist' + - Node Package for Server-side Charts - - 'ng-chartist.js' - Angular Directive From 2e3685ca06b6aa681c559f74841d627902d59184 Mon Sep 17 00:00:00 2001 From: Rory Hunter Date: Thu, 26 Nov 2015 12:17:52 +0000 Subject: [PATCH 336/593] Fix updateCurrentOptions to expect a media query event --- src/scripts/core.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index e7a70962..0758f7f3 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -886,7 +886,7 @@ var Chartist = { mediaQueryListeners = [], i; - function updateCurrentOptions(preventChangedEvent) { + function updateCurrentOptions(mediaEvent) { var previousOptions = currentOptions; currentOptions = Chartist.extend({}, baseOptions); @@ -899,7 +899,7 @@ var Chartist = { } } - if(eventEmitter && !preventChangedEvent) { + if(eventEmitter && mediaEvent) { eventEmitter.emit('optionsChanged', { previousOptions: previousOptions, currentOptions: currentOptions @@ -923,8 +923,8 @@ var Chartist = { mediaQueryListeners.push(mql); } } - // Execute initially so we get the correct options - updateCurrentOptions(true); + // Execute initially without an event argument so we get the correct options + updateCurrentOptions(); return { removeMediaQueryListeners: removeMediaQueryListeners, From b3aee95b4c7ed2249ecdbf25feecabf02ca31c91 Mon Sep 17 00:00:00 2001 From: madflow Date: Tue, 8 Dec 2015 20:12:49 +0100 Subject: [PATCH 337/593] Fix copy pasta --- site/data/pages/plugins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index ca8988d5..1bdcfce4 100755 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -253,7 +253,7 @@ sections: - Moxx - - 'Link:' - - 'chartist-plugin-threshold' + - 'chartist-plugin-fill-donut' - type: sub-section data: title: Zoom Plugin From b0cdcfe82a02c6d35c0f078db050bb3913c9cf7f Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Sat, 12 Dec 2015 13:36:29 -0800 Subject: [PATCH 338/593] Fixed misspelling in overlapping bars example The original overlapping bars example spelled the month of May as "Mai". --- site/examples/overlapping-bars.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/examples/overlapping-bars.js b/site/examples/overlapping-bars.js index a8f16db1..8df7b813 100644 --- a/site/examples/overlapping-bars.js +++ b/site/examples/overlapping-bars.js @@ -1,5 +1,5 @@ var data = { - labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], series: [ [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8], [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4] @@ -21,4 +21,4 @@ var responsiveOptions = [ }] ]; -new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Bar('.ct-chart', data, options, responsiveOptions); From 446248596b00f6cb306ac7f0d735fecb2f0f1b38 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Wed, 16 Dec 2015 10:41:07 +0100 Subject: [PATCH 339/593] Add fdescribe and fit to jshintrc. --- test/.jshintrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/.jshintrc b/test/.jshintrc index b0aa0ed4..f0bcac8a 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -26,9 +26,11 @@ "beforeEach": false, "browser": false, "describe": false, + "fdescribe": false, "expect": false, "inject": false, "it": false, + "fit": false, "jasmine": false, "spyOn": false, "$": false, From d4fe5100ca6695a26a71d140a8af80881e0e1606 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Wed, 16 Dec 2015 10:42:53 +0100 Subject: [PATCH 340/593] Fix #527 Pie render issue with small angles. --- src/scripts/charts/pie.js | 2 +- test/spec/spec-pie-chart.js | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 56728183..ca7caf41 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -164,7 +164,7 @@ endAngle -= 0.01; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); // 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 diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 4968e567..7df928b6 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -98,11 +98,39 @@ describe('Pie chart tests', function() { expect(labels.eq(2).text()).toBe('33%'); done(); }); - }); + }); + describe('Pie with small ratio', function() { + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var data = { + series: [0.001, 2] + }; + var options = { + width: 100, + height: 100, + chartPadding: 0, + }; + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('should render correctly with very small slices', function(done) { + onCreated(function() { + + var slice1 = $('.ct-slice-pie').eq(0); + var slice2 = $('.ct-slice-pie').eq(1); + expect(slice1.attr('d')).toMatch(/^M50,0A50,50,0,1,0,50.1\d+,0/); + expect(slice2.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/); + done(); + }); + }); + + }); describe('Gauge Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#gauge-chart From ec00b726030a8b5ec90b263a0cca7a65dc98b4f3 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Thu, 17 Dec 2015 10:49:03 +0100 Subject: [PATCH 341/593] Fix pie render issues with overlaps and full circle arcs. --- src/scripts/charts/pie.js | 12 ++-- test/spec/spec-pie-chart.js | 126 ++++++++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 24 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index ca7caf41..01cdde8c 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -158,13 +158,17 @@ ].join(' ')); var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + + // Use slight offset so there are no transparent hairline issues + var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; + if(endAngle - overlappigStartAngle >= 359.99) { + endAngle = overlappigStartAngle + 359.99; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle), + var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); // 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 @@ -239,7 +243,7 @@ } } - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; } diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 7df928b6..7da5041a 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -37,12 +37,14 @@ describe('Pie chart tests', function() { describe('Simple Pie Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#simple-pie-chart - function onCreated(callback) { - jasmine.getFixtures().set('
    '); - var data = { + var num = '\\d+(\\.\\d*)?'; + var data, options; + + beforeEach(function() { + data = { series: [5, 3, 4] }; - var options = { + options = { width: 100, height: 100, chartPadding: 10, @@ -50,9 +52,11 @@ describe('Pie chart tests', function() { return Math.round(value / data.series.reduce(sum) * 100) + '%'; } }; - var sum = function(a, b) { return a + b; }; - + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); var chart = new Chartist.Pie('.ct-chart', data, options); chart.on('created', callback); } @@ -77,8 +81,6 @@ describe('Pie chart tests', function() { it('should create slice path', function(done) { onCreated(function() { $('.ct-slice-pie').each(function() { - - var num = '\\d+(\\.\\d*)?'; var pattern = '^M' + num + ',' + num + 'A40,40,0,0,0,' + num + ',' + num + @@ -99,36 +101,120 @@ describe('Pie chart tests', function() { done(); }); }); + + it('should overlap slices', function(done) { + data = { + series: [1, 1] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + var slice2 = $('.ct-slice-pie').eq(1); - }); + expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,0,0,50.\d+,90L50,50Z/); + expect(slice2.attr('d')).toMatch(/^M50,90A40,40,0,0,0,50,10L50,50Z/); + done(); + }); + }); + + it('should set large arc sweep flag', function(done) { + data = { + series: [1, 2] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,1,0/); + done(); + }, data); + }); - describe('Pie with small ratio', function() { + it('should draw complete circle with gap', function(done) { + data = { + series: [1] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + expect(slice1.attr('d')).toMatch(/^M49.9\d+,10A40,40,0,1,0,50,10L50,50Z/); + done(); + }); + }); - function onCreated(callback) { - jasmine.getFixtures().set('
    '); - var data = { + it('should draw complete circle with startAngle', function(done) { + data.series = [100]; + options.startAngle = 90; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + expect(slice1.attr('d')).toMatch(/^M90,49.9\d+A40,40,0,1,0,90,50L50,50Z/); + done(); + }); + }); + + it('should draw complete circle if values are 0', function(done) { + data = { + series: [0, 1, 0] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(1); + expect(slice1.attr('d')).toMatch(/^M49.9\d+,10A40,40,0,1,0,50,10L50,50Z/); + done(); + }); + }); + + }); + + describe('Pie with small slices', function() { + var data, options; + + beforeEach(function() { + data = { series: [0.001, 2] }; - var options = { + options = { width: 100, height: 100, chartPadding: 0, - }; + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); var chart = new Chartist.Pie('.ct-chart', data, options); chart.on('created', callback); } - - it('should render correctly with very small slices', function(done) { - onCreated(function() { + it('Pie should render correctly with very small slices', function(done) { + onCreated(function() { var slice1 = $('.ct-slice-pie').eq(0); - var slice2 = $('.ct-slice-pie').eq(1); + var slice2 = $('.ct-slice-pie').eq(1); - expect(slice1.attr('d')).toMatch(/^M50,0A50,50,0,1,0,50.1\d+,0/); + expect(slice1.attr('d')).toMatch(/^M49.9\d*,0A50,50,0,1,0,50,0/); expect(slice2.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/); done(); }); }); + + it('Pie should render correctly with very small slices on startAngle', function(done) { + options.startAngle = 90; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + var slice2 = $('.ct-slice-pie').eq(1); + + expect(slice1.attr('d')).toMatch(/^M100,49.97\d*A50,50,0,1,0,100,49.98\d*/); + expect(slice2.attr('d')).toMatch(/^M100,50.1\d*A50,50,0,0,0,100,50/); + done(); + }); + }); + + it('Donut should render correctly with very small slices', function(done) { + options.donut = true; + onCreated(function() { + var slice1 = $('.ct-slice-donut').eq(0); + var slice2 = $('.ct-slice-donut').eq(1); + + expect(slice1.attr('d')).toMatch(/^M49.9\d*,30A20,20,0,1,0,50,30/); + expect(slice2.attr('d')).toMatch(/^M50.\d+,30A20,20,0,0,0,50,30/); + done(); + }); + }); }); From 61a12885fa36a153f2a62cb3ee4811c732ad381d Mon Sep 17 00:00:00 2001 From: Carlos Morales Date: Tue, 22 Dec 2015 13:55:04 +0100 Subject: [PATCH 342/593] fixes #537: Error on empty data set --- src/scripts/core.js | 5 ++++- src/scripts/interpolation.js | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index e7a70962..96d2b6eb 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -511,9 +511,12 @@ var Chartist = { } else if (highLow.low < 0) { // If we have the same negative value for the bounds we set bounds.high to 0 highLow.high = 0; - } else { + } else if (highLow.high > 0) { // If we have the same positive value for the bounds we set bounds.low to 0 highLow.low = 0; + } else { + // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors + highLow.high = highLow.low = 0; } } diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 8058d941..2c38f7b5 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -200,10 +200,13 @@ // This is necessary to treat "holes" in line charts var segments = splitIntoSegments(pathCoordinates, valueData); - // If the split resulted in more that one segment we need to interpolate each segment individually and join them - // afterwards together into a single path. - if(segments.length > 1) { - var paths = []; + if(!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return Chartist.Interpolation.none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; // For each segment we will recurse the cardinal function segments.forEach(function(segment) { paths.push(cardinal(segment.pathCoordinates, segment.valueData)); From 01a9a0f4e1dd11eec59a3d89d93409c0f728bdfd Mon Sep 17 00:00:00 2001 From: Xiao Hanyu Date: Fri, 25 Dec 2015 20:51:20 +0800 Subject: [PATCH 343/593] Update getting-started.yml --- site/data/pages/getting-started.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 48071abe..25591c95 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -571,7 +571,7 @@ sections: - type: text data: text: > - In the following chapter you'll find some advanced usage examples that might be of interesst for you. + In the following chapter you'll find some advanced usage examples that might be of interest for you. Chartist is very flexible because it relies on standard technology. This also means that you will need to implement certain things yourself. This topic should cover some of these use-cases and give you some basic idea why and how to implement certain functionality. From e28c2bba321acae4843939a615646b4030e12006 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Wed, 6 Jan 2016 15:48:16 +0000 Subject: [PATCH 344/593] Add Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9dcf99c5..348946be 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # Big welcome by the Chartist Guy + +[![Join the chat at https://gitter.im/gionkunz/chartist-js](https://badges.gitter.im/gionkunz/chartist-js.svg)](https://gitter.im/gionkunz/chartist-js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![npm version](http://img.shields.io/npm/v/chartist.svg)](https://npmjs.org/package/chartist) [![build status](http://img.shields.io/travis/gionkunz/chartist-js.svg)](https://travis-ci.org/gionkunz/chartist-js) [![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) ![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") From 6497a9188cc74cda7a0dd508b2bc315098876bfa Mon Sep 17 00:00:00 2001 From: Stephen Date: Sun, 10 Jan 2016 16:01:29 +0000 Subject: [PATCH 345/593] Allow empty pie chart values to be ignored Empty pie chart values can render with overlapping labels. This adds a configuration option to allow them to be ignored when rendering the pie chart. --- src/scripts/charts/pie.js | 7 +++- test/spec/spec-pie-chart.js | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 01cdde8c..8a57bb78 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -48,7 +48,9 @@ // 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. labelDirection: 'neutral', // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. - reverseData: false + reverseData: false, + // If true empty values will be ignored to avoid drawing unncessary slices and labels + ignoreEmptyValues: false }; /** @@ -143,6 +145,9 @@ // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { + // If current value is zero and we are ignoring empty values then skip to next value + if (dataArray[i] === 0 && options.ignoreEmptyValues) continue; + var series = this.data.series[i]; seriesGroups[i] = this.svg.elem('g', null, null, true); diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 7da5041a..f83d900c 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -217,6 +217,75 @@ describe('Pie chart tests', function() { }); }); + + describe('Pie with some empty values configured to be ignored', function() { + var data, options; + + beforeEach(function() { + data = { + series: [1, 2, 0, 4] + }; + options = { + width: 100, + height: 100, + ignoreEmptyValues: true + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('Pie should not render empty slices', function(done) { + onCreated(function() { + var slices = $('.ct-slice-pie'); + + expect(slices.length).toBe(3); + + expect(slices.eq(2).attr('ct:value')).toBe('1'); + expect(slices.eq(1).attr('ct:value')).toBe('2'); + expect(slices.eq(0).attr('ct:value')).toBe('4'); + done(); + }); + }); + }); + + describe('Pie with some empty values configured not to be ignored', function() { + var data, options; + + beforeEach(function() { + data = { + series: [1, 2, 0, 4] + }; + options = { + width: 100, + height: 100, + ignoreEmptyValues: false + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('Pie should render empty slices', function(done) { + onCreated(function() { + var slices = $('.ct-slice-pie'); + + expect(slices.length).toBe(4); + + expect(slices.eq(3).attr('ct:value')).toBe('1'); + expect(slices.eq(2).attr('ct:value')).toBe('2'); + expect(slices.eq(1).attr('ct:value')).toBe('0'); + expect(slices.eq(0).attr('ct:value')).toBe('4'); + done(); + }); + }); + }); describe('Gauge Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#gauge-chart From 8356b883db0da593d6610a4f4d14fd25b624f317 Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 02:16:16 -0500 Subject: [PATCH 346/593] render 0 in ct:value attribute for line graphs --- src/scripts/charts/line.js | 2 +- test/spec/spec-line-chart.js | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 00616e04..afe8437b 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -206,7 +206,7 @@ y2: pathElement.y }, options.classNames.point).attr({ 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { - return v; + return v || v === 0; }).join(','), 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index c16ddf72..f6c4bc17 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -9,6 +9,52 @@ describe('Line chart tests', function () { }); + describe('ct:value attribute', function () { + it('should contain x and y value for each datapoint', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + series: [[ + {x: 1, y: 2}, + {x: 3, y: 4} + ]] + }, { + axisX: { + type: Chartist.FixedScaleAxis + } + }); + + chart.on('created', function () { + expect($('.ct-point').eq(0).attr('ct:value')).toEqual('1,2'); + expect($('.ct-point').eq(1).attr('ct:value')).toEqual('3,4'); + done(); + }); + }); + + it('should render values that are zero', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + series: [[ + {x: 0, y: 1}, + {x: 1, y: 0}, + {x: 0, y: 0} + ]] + }, { + axisX: { + type: Chartist.FixedScaleAxis + } + }); + + chart.on('created', function () { + expect($('.ct-point').eq(0).attr('ct:value')).toEqual('0,1'); + expect($('.ct-point').eq(1).attr('ct:value')).toEqual('1,0'); + expect($('.ct-point').eq(2).attr('ct:value')).toEqual('0,0'); + done(); + }); + }); + }); + describe('Meta data tests', function () { it('should render meta data correctly with mixed value array', function (done) { jasmine.getFixtures().set('
    '); From f3a433efe493b0af59b52446e97ca031a5ea1cb1 Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 10:59:53 -0500 Subject: [PATCH 347/593] use === since it's comparing primitives --- test/spec/spec-line-chart.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index f6c4bc17..1daa7a3c 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -25,8 +25,8 @@ describe('Line chart tests', function () { }); chart.on('created', function () { - expect($('.ct-point').eq(0).attr('ct:value')).toEqual('1,2'); - expect($('.ct-point').eq(1).attr('ct:value')).toEqual('3,4'); + expect($('.ct-point').eq(0).attr('ct:value')).toBe('1,2'); + expect($('.ct-point').eq(1).attr('ct:value')).toBe('3,4'); done(); }); }); @@ -47,9 +47,9 @@ describe('Line chart tests', function () { }); chart.on('created', function () { - expect($('.ct-point').eq(0).attr('ct:value')).toEqual('0,1'); - expect($('.ct-point').eq(1).attr('ct:value')).toEqual('1,0'); - expect($('.ct-point').eq(2).attr('ct:value')).toEqual('0,0'); + expect($('.ct-point').eq(0).attr('ct:value')).toBe('0,1'); + expect($('.ct-point').eq(1).attr('ct:value')).toBe('1,0'); + expect($('.ct-point').eq(2).attr('ct:value')).toBe('0,0'); done(); }); }); From 5b79ae7775834261ac2bf8d69f2a7e57f0427a6c Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 11:13:24 -0500 Subject: [PATCH 348/593] ensure ct:value has values that are zero --- src/scripts/charts/bar.js | 2 +- test/spec/spec-bar-chart.js | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 77e73853..23c81247 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -347,7 +347,7 @@ // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'value': [value.x, value.y].filter(function(v) { - return v; + return v || v === 0; }).join(','), 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); diff --git a/test/spec/spec-bar-chart.js b/test/spec/spec-bar-chart.js index e110b7a0..026dab47 100644 --- a/test/spec/spec-bar-chart.js +++ b/test/spec/spec-bar-chart.js @@ -9,6 +9,52 @@ describe('Bar chart tests', function() { }); + describe('ct:value attribute', function() { + it('should contain x and y value for each bar', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', { + series: [[ + {x: 1, y: 2}, + {x: 3, y: 4} + ]] + }, { + axisX: { + type: Chartist.AutoScaleAxis + } + }); + + chart.on('created', function() { + expect($('.ct-bar').eq(0).attr('ct:value')).toEqual('1,2'); + expect($('.ct-bar').eq(1).attr('ct:value')).toEqual('3,4'); + done(); + }); + }); + + it('should render values that are zero', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', { + series: [[ + {x: 0, y: 1}, + {x: 2, y: 0}, + {x: 0, y: 0} + ]] + }, { + axisX: { + type: Chartist.AutoScaleAxis + } + }); + + chart.on('created', function() { + expect($('.ct-bar').eq(0).attr('ct:value')).toEqual('0,1'); + expect($('.ct-bar').eq(1).attr('ct:value')).toEqual('2,0'); + expect($('.ct-bar').eq(2).attr('ct:value')).toEqual('0,0'); + done(); + }); + }); + }); + describe('Meta data tests', function () { it('should render meta data correctly with mixed value array', function(done) { jasmine.getFixtures().set('
    '); From e6d66ce8afa20ff3fcdccbdecae578082bbdaf78 Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 11:20:04 -0500 Subject: [PATCH 349/593] use helper to filter out non-numbers --- src/scripts/charts/bar.js | 4 +--- src/scripts/charts/line.js | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 23c81247..6429d56e 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -346,9 +346,7 @@ // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': [value.x, value.y].filter(function(v) { - return v || v === 0; - }).join(','), + 'value': [value.x, value.y].filter(Chartist.isNum).join(','), 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index afe8437b..2ec06d42 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -205,9 +205,7 @@ x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { - return v || v === 0; - }).join(','), + 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); From 79e00f6b5c3d4dbca57110945ae0e26110622324 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:17:56 +0100 Subject: [PATCH 350/593] Removed workaround and fallback for SVG element width and height calculations, fixes #592 --- src/scripts/svg.js | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index c31a67b0..0256ab4b 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -311,43 +311,23 @@ } /** - * "Save" way to get property value from svg BoundingBox. - * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node. - * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/) - * - * @memberof Chartist.Svg - * @param {SVGElement} node The svg node to - * @param {String} prop The property to fetch (ex.: height, width, ...) - * @returns {Number} The value of the given bbox property - */ - function getBBoxProperty(node, prop) { - try { - return node.getBBox()[prop]; - } catch(e) {} - - return 0; - } - - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element height using `getBoundingClientRect` * * @memberof Chartist.Svg * @return {Number} The elements height in pixels */ function height() { - return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight; + return this._node.getBoundingClientRect().height; } /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element width using `getBoundingClientRect` * * @memberof Chartist.Core * @return {Number} The elements width in pixels */ function width() { - return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth; + return this._node.getBoundingClientRect().width; } /** From de4728de67d14cb1edf7d220c90a62a0adca2542 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:27:05 +0100 Subject: [PATCH 351/593] Removed serialization of values on line chart areas, fixes #424 --- src/scripts/charts/line.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 2ec06d42..c37f1bc7 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -281,9 +281,7 @@ // and adding the created DOM elements to the correct series group var area = seriesElement.elem('path', { d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': data.normalized[seriesIndex] - }, Chartist.xmlNs.uri); + }, options.classNames.area, true); // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { From 7e3d946cb88db1c205f76f3c10c288b35f476923 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:29:21 +0100 Subject: [PATCH 352/593] Removed onlyInteger setting from default bar chart settings, fixes #423 --- src/scripts/charts/bar.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 6429d56e..1320f195 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -65,8 +65,6 @@ high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, - // Use only integer values (whole numbers) for the scale steps - onlyInteger: false, // 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} chartPadding: { top: 15, From 9a7d01bb30e3817dabdfa35bd6558a07c41bdb54 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:44:13 +0100 Subject: [PATCH 353/593] Adding unminified CSS to dist output, fixes #506 --- tasks/aliases.yml | 4 ++-- tasks/copy.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tasks/aliases.yml b/tasks/aliases.yml index 0142ed10..ea64d2f5 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -12,13 +12,13 @@ default: # create the library build: - 'clean:dist' + - 'sass:dist' + - 'cssmin' - 'copy:dist' - 'concat:dist' - 'template:dist' - 'umd' - 'uglify:dist' - - 'sass:dist' - - 'cssmin' # prepare the website public: diff --git a/tasks/copy.js b/tasks/copy.js index 3b99c9cc..ec2c28f8 100644 --- a/tasks/copy.js +++ b/tasks/copy.js @@ -55,6 +55,12 @@ module.exports = function (grunt) { '*.scss' ] }, + { + expand: true, + cwd: '.tmp/styles', + dest: '<%= pkg.config.dist %>/', + src: 'chartist.css*' + }, { dest: '<%= pkg.config.dist %>/', src: 'LICENSE' From b7c16ddeb7dcbbba8cc253725c9751dcb4e90a4e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 21:07:38 +0100 Subject: [PATCH 354/593] Allow charts to be created without data and labels, fixes #598, fixes #588, fixes #537, fixes #425 --- src/scripts/axes/axis.js | 2 +- src/scripts/charts/bar.js | 3 +- src/scripts/charts/line.js | 1 + src/scripts/charts/pie.js | 5 +- src/scripts/core.js | 41 ++++++++++- test/spec/spec-bar-chart.js | 133 +++++++++++++++++++++++++++++++++++ test/spec/spec-line-chart.js | 90 ++++++++++++++++++++++++ 7 files changed, 270 insertions(+), 5 deletions(-) diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 4ea910a5..bca56876 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -56,7 +56,7 @@ } // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!labelValues[index] && labelValues[index] !== 0) { + if(!Chartist.isFalseyButZero(labelValues[index]) && !labelValues[index] === '') { return; } diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 1320f195..673c8acd 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -107,6 +107,7 @@ * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { @@ -129,7 +130,7 @@ var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); - if(options.stackBars) { + if(options.stackBars && data.normalized.length !== 0) { // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index c37f1bc7..5fa8d9dd 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -111,6 +111,7 @@ * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: Chartist.getDataArray(this.data, options.reverseData, true) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 8a57bb78..b22cfef9 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -81,6 +81,7 @@ * @param options */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var seriesGroups = [], labelsGroup, chartRect, @@ -166,7 +167,7 @@ // Use slight offset so there are no transparent hairline issues var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); - + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees if(endAngle - overlappigStartAngle >= 359.99) { @@ -226,7 +227,7 @@ if(options.showLabel) { // Position at the labelRadius distance from center and between start and end angle var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { diff --git a/src/scripts/core.js b/src/scripts/core.js index 96d2b6eb..e403e1d5 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -309,6 +309,44 @@ var Chartist = { return svg; }; + /** + * Ensures that the data object passed as second argument to the charts is present and correctly initialized. + * + * @param {Object} data The data object that is passed as second argument to the charts + * @return {Object} The normalized data object + */ + Chartist.normalizeData = function(data) { + // Ensure data is present otherwise enforce + data = data || {series: [], labels: []}; + data.series = data.series || []; + data.labels = data.labels || []; + + // Check if we should generate some labels based on existing series data + if (data.series.length > 0 && data.labels.length === 0) { + var normalized = Chartist.getDataArray(data), + labelCount; + + // If all elements of the normalized data array are arrays we're dealing with + // data from Bar or Line charts and we need to find the largest series if they are un-even + if (normalized.every(function(value) { + return value instanceof Array; + })) { + // Getting the series with the the most elements + labelCount = Math.max.apply(null, normalized.map(function(series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = normalized.length; + } + + // Setting labels to an array with emptry strings using our labelCount estimated above + data.labels = Chartist.times(labelCount).map(function() { + return ''; + }); + } + return data; + }; /** * Reverses the series, labels and series data arrays. @@ -516,7 +554,8 @@ var Chartist = { highLow.low = 0; } else { // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors - highLow.high = highLow.low = 0; + highLow.high = 1; + highLow.low = 0; } } diff --git a/test/spec/spec-bar-chart.js b/test/spec/spec-bar-chart.js index 026dab47..c726c4f7 100644 --- a/test/spec/spec-bar-chart.js +++ b/test/spec/spec-bar-chart.js @@ -141,4 +141,137 @@ describe('Bar chart tests', function() { }); }); }); + + describe('Empty data tests', function () { + it('should render empty grid with no data', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart'); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with only labels', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + labels: [1, 2, 3, 4] + }; + var chart = new Chartist.Bar('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Find exactly as many horizontal grid lines as labels were specified (Step Axis) + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(data.labels.length); + done(); + }); + }); + + it('should generate labels and render empty grid with only series in data', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + series: [ + [1, 2, 3, 4], + [2, 3, 4], + [3, 4] + ] + }; + var chart = new Chartist.Bar('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Should generate the labels using the largest series count + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(Math.max.apply(null, data.series.map(function(series) { + return series.length; + }))); + done(); + }); + }); + + it('should render empty grid with no data and specified high low', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + width: 400, + height: 300, + high: 100, + low: -100 + }); + + chart.on('created', function () { + // Find first and last label + var labels = document.querySelectorAll('.ct-labels .ct-label.ct-vertical'); + var firstLabel = labels[0]; + var lastLabel = labels[labels.length - 1]; + + expect(firstLabel.textContent).toBe('-100'); + expect(lastLabel.textContent).toBe('100'); + done(); + }); + }); + + it('should render empty grid with no data and reverseData option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + reverseData: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and stackBars option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + stackBars: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and horizontalBars option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + horizontalBars: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + // TODO: In theory the axis should be created with ct-horizontal class + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and distributeSeries option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + distributeSeries: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + }); }); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index 1daa7a3c..b4cf31fe 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -313,4 +313,94 @@ describe('Line chart tests', function () { }); }); }); + + describe('Empty data tests', function () { + it('should render empty grid with no data', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart'); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with only labels', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + labels: [1, 2, 3, 4] + }; + var chart = new Chartist.Line('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Find exactly as many horizontal grid lines as labels were specified (Step Axis) + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(data.labels.length); + done(); + }); + }); + + it('should generate labels and render empty grid with only series in data', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + series: [ + [1, 2, 3, 4], + [2, 3, 4], + [3, 4] + ] + }; + var chart = new Chartist.Line('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Should generate the labels using the largest series count + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(Math.max.apply(null, data.series.map(function(series) { + return series.length; + }))); + done(); + }); + }); + + it('should render empty grid with no data and specified high low', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', null, { + width: 400, + height: 300, + high: 100, + low: -100 + }); + + chart.on('created', function () { + // Find first and last label + var labels = document.querySelectorAll('.ct-labels .ct-label.ct-vertical'); + var firstLabel = labels[0]; + var lastLabel = labels[labels.length - 1]; + + expect(firstLabel.textContent).toBe('-100'); + expect(lastLabel.textContent).toBe('100'); + done(); + }); + }); + + it('should render empty grid with no data and reverseData option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', null, { + reverseData: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + }); }); From 5ffb364380c432b786a30017f593b9fbeb60beb0 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 17 Feb 2016 14:41:57 +1100 Subject: [PATCH 355/593] Fixed typo --- site/data/pages/examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index e0084c29..28b28cc4 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -159,7 +159,7 @@ sections: classes: ct-golden-section intro: > Chartist will figure out if your browser supports foreignObject and it will use them to create labels - that re based on regular HTML text elements. Multi-line and regular CSS styles are just two of many + that are based on regular HTML text elements. Multi-line and regular CSS styles are just two of many benefits while using foreignObjects! - type: live-example data: From 312affb3d07ad94a9ebc64725c5106347c7b14d9 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 17 Feb 2016 14:51:40 +1100 Subject: [PATCH 356/593] Fixed typo --- src/scripts/charts/line.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 5fa8d9dd..df3cdacb 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -368,7 +368,7 @@ * ] * }; * - * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. + * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. * var responsiveOptions = [ * ['screen and (min-width: 641px) and (max-width: 1024px)', { * showPoint: false, From 84308adef112214babea2c6bb350335774067400 Mon Sep 17 00:00:00 2001 From: Prayag Verma Date: Fri, 19 Feb 2016 19:11:08 +0530 Subject: [PATCH 357/593] Fix a typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Reponsive` → `Responsive` --- site/data/pages/index.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 2a61c4d8..150b0204 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -167,7 +167,7 @@ sections: - name: iOS Safari 7 status: supported text: Supported - - name: Reponsive Options Override + - name: Responsive Options Override browsers: - name: IE9* status: supported From dc2928df94db2be7c14878ae6bc90b4bd55c3168 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 21 Feb 2016 09:42:40 +0100 Subject: [PATCH 358/593] Added nvmrc file with currently used node version --- .nvmrc | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..7fd9b020 --- /dev/null +++ b/.nvmrc @@ -0,0 +1,2 @@ +v0.10.35 + From cd2a6c75569d06b2daa69a01e70d459025b375f4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 21 Feb 2016 10:29:41 +0100 Subject: [PATCH 359/593] Refactored namespaced attribute handling, fixes #584 --- src/scripts/charts/bar.js | 12 ++++++------ src/scripts/charts/line.js | 12 ++++++------ src/scripts/charts/pie.js | 10 +++++----- src/scripts/core.js | 16 +++++++++++++++- src/scripts/svg.js | 25 +++++++++---------------- test/spec/spec-svg.js | 19 +++++++++++++++++++ 6 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 673c8acd..0e3c7fa4 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -254,9 +254,9 @@ // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -345,9 +345,9 @@ // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': [value.x, value.y].filter(Chartist.isNum).join(','), - 'meta': Chartist.getMetaData(series, valueIndex) - }, Chartist.xmlNs.uri); + 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','), + 'ct:meta': Chartist.getMetaData(series, valueIndex) + }); this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 5fa8d9dd..8c92c938 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -154,9 +154,9 @@ // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -206,9 +206,9 @@ x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), - 'meta': pathElement.data.meta - }, Chartist.xmlNs.uri); + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), + 'ct:meta': pathElement.data.meta + }); this.eventEmitter.emit('draw', { type: 'point', diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index b22cfef9..091b35ff 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -154,8 +154,8 @@ // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[i].attr({ - 'series-name': series.name - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name + }); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -195,9 +195,9 @@ // Adding the pie series value to the path pathElement.attr({ - 'value': dataArray[i], - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:value': dataArray[i], + 'ct:meta': Chartist.serialize(series.meta) + }); // If this is a donut, we add the stroke-width as style attribute if(options.donut) { diff --git a/src/scripts/core.js b/src/scripts/core.js index e403e1d5..c1b1d587 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -10,6 +10,20 @@ var Chartist = { (function (window, document, Chartist) { 'use strict'; + /** + * This object contains all namespaces used within Chartist. + * + * @memberof Chartist.Core + * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}} + */ + Chartist.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' + }; + /** * Helps to simplify functional style code * @@ -290,7 +304,7 @@ var Chartist = { // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttributeNS('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix); + return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct'); }).forEach(function removePreviousElement(svg) { container.removeChild(svg); }); diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 0256ab4b..be20ade4 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -7,16 +7,6 @@ (function(window, document, Chartist) { 'use strict'; - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; - - Chartist.xmlNs = { - qualifiedName: 'xmlns:ct', - prefix: 'ct', - uri: 'http://gionkunz.github.com/chartist-js/ct' - }; - /** * 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. * @@ -33,11 +23,13 @@ if(name instanceof Element) { this._node = name; } else { - this._node = document.createElementNS(svgNs, name); + this._node = document.createElementNS(Chartist.namespaces.svg, name); // If this is an SVG element created then custom namespace if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + this.attr({ + 'xmlns:ct': Chartist.namespaces.ct + }); } } @@ -63,7 +55,7 @@ * * @memberof Chartist.Svg * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @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. * @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. */ function attr(attributes, ns) { @@ -81,8 +73,9 @@ return; } - if(ns) { - this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + if (key.indexOf(':') !== -1) { + var namespacedAttribute = key.split(':'); + this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]); } else { this._node.setAttribute(key, attributes[key]); } @@ -173,7 +166,7 @@ } // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); + content.setAttribute('xmlns', Chartist.namespaces.xmlns); // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) diff --git a/test/spec/spec-svg.js b/test/spec/spec-svg.js index f997242d..0abfa8ec 100644 --- a/test/spec/spec-svg.js +++ b/test/spec/spec-svg.js @@ -65,6 +65,25 @@ describe('Chartist SVG', function () { expect(svg._node.firstChild.attributes.r.textContent).toBe('10'); }); + it('should allow to set namespaced attributes', function () { + var svg = new window.Chartist.Svg('image'); + svg.elem('image').attr({ + x: 100, + y: 100, + height: 100, + width: 100, + 'xlink:href': 'image.jpg' + }); + + expect(svg._node).toBeDefined(); + expect(svg._node.firstChild).toBeDefined(); + expect(svg._node.firstChild.getAttribute('x')).toBe('100'); + expect(svg._node.firstChild.getAttribute('y')).toBe('100'); + expect(svg._node.firstChild.getAttribute('width')).toBe('100'); + expect(svg._node.firstChild.getAttribute('height')).toBe('100'); + expect(svg._node.firstChild.getAttributeNS(Chartist.namespaces.xlink, 'href')).toBe('image.jpg'); + }); + it('should clear on each nesting level', function () { var svg = new window.Chartist.Svg('svg'); var group = svg.elem('g'); From 5bd8c919691cfae940e0d39e80017f30991b0cb2 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 21 Feb 2016 10:46:31 +0100 Subject: [PATCH 360/593] Added dual licensing WTFPL and MIT, built new version --- LICENSE-MIT | 7 + LICENSE => LICENSE-WTFPL | 2 +- dist/LICENSE | 13 - dist/chartist.css | 592 +++++++++++++++++++++++++++++++++++++++ dist/chartist.css.map | 11 + dist/chartist.js | 211 ++++++++------ dist/chartist.min.js | 13 +- dist/chartist.min.js.map | 2 +- package.json | 10 +- 9 files changed, 750 insertions(+), 111 deletions(-) create mode 100644 LICENSE-MIT rename LICENSE => LICENSE-WTFPL (89%) delete mode 100644 dist/LICENSE create mode 100644 dist/chartist.css create mode 100644 dist/chartist.css.map diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..976cde6e --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,7 @@ +Copyright (c) 2013 Gion Kunz + +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: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE b/LICENSE-WTFPL similarity index 89% rename from LICENSE rename to LICENSE-WTFPL index 5c93f456..792ed5b9 100644 --- a/LICENSE +++ b/LICENSE-WTFPL @@ -1,7 +1,7 @@ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 - Copyright (C) 2004 Sam Hocevar + Copyright (c) 2013 Gion Kunz Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long diff --git a/dist/LICENSE b/dist/LICENSE deleted file mode 100644 index 5c93f456..00000000 --- a/dist/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/dist/chartist.css b/dist/chartist.css new file mode 100644 index 00000000..8f06df02 --- /dev/null +++ b/dist/chartist.css @@ -0,0 +1,592 @@ +.ct-label { + fill: rgba(0, 0, 0, 0.4); + color: rgba(0, 0, 0, 0.4); + font-size: 0.75rem; + line-height: 1; } + +.ct-chart-line .ct-label, .ct-chart-bar .ct-label { + display: block; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; } + +.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, 0.2); + stroke-width: 1px; + stroke-dasharray: 2px; } + +.ct-point { + stroke-width: 10px; + stroke-linecap: round; } + +.ct-line { + fill: none; + stroke-width: 4px; } + +.ct-area { + stroke: none; + fill-opacity: 0.1; } + +.ct-bar { + fill: none; + stroke-width: 10px; } + +.ct-slice-donut { + fill: none; + stroke-width: 60px; } + +.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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .ct-double-octave > svg { + display: block; + position: absolute; + top: 0; + left: 0; } + +/*# sourceMappingURL=chartist.css.map */ \ No newline at end of file diff --git a/dist/chartist.css.map b/dist/chartist.css.map new file mode 100644 index 00000000..d1353ddc --- /dev/null +++ b/dist/chartist.css.map @@ -0,0 +1,11 @@ +{ + "version": 3, + "file": "chartist.css", + "sources": [ + "../../chartist.scss", + "../../settings/_chartist-settings.scss" + ], + "sourcesContent": [], + "mappings": "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", + "names": [] +} \ No newline at end of file diff --git a/dist/chartist.js b/dist/chartist.js index 5588129e..497d2d8e 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,10 +14,11 @@ } }(this, function () { -/* Chartist.js 0.9.5 - * Copyright © 2015 Gion Kunz - * Free to use under the WTFPL license. - * http://www.wtfpl.net/ +/* Chartist.js 0.9.6 + * Copyright © 2016 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 */ /** * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. @@ -25,12 +26,26 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.5' + version: '0.9.6' }; (function (window, document, Chartist) { 'use strict'; + /** + * This object contains all namespaces used within Chartist. + * + * @memberof Chartist.Core + * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}} + */ + Chartist.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' + }; + /** * Helps to simplify functional style code * @@ -311,7 +326,7 @@ var Chartist = { // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttributeNS('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix); + return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct'); }).forEach(function removePreviousElement(svg) { container.removeChild(svg); }); @@ -330,6 +345,44 @@ var Chartist = { return svg; }; + /** + * Ensures that the data object passed as second argument to the charts is present and correctly initialized. + * + * @param {Object} data The data object that is passed as second argument to the charts + * @return {Object} The normalized data object + */ + Chartist.normalizeData = function(data) { + // Ensure data is present otherwise enforce + data = data || {series: [], labels: []}; + data.series = data.series || []; + data.labels = data.labels || []; + + // Check if we should generate some labels based on existing series data + if (data.series.length > 0 && data.labels.length === 0) { + var normalized = Chartist.getDataArray(data), + labelCount; + + // If all elements of the normalized data array are arrays we're dealing with + // data from Bar or Line charts and we need to find the largest series if they are un-even + if (normalized.every(function(value) { + return value instanceof Array; + })) { + // Getting the series with the the most elements + labelCount = Math.max.apply(null, normalized.map(function(series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = normalized.length; + } + + // Setting labels to an array with emptry strings using our labelCount estimated above + data.labels = Chartist.times(labelCount).map(function() { + return ''; + }); + } + return data; + }; /** * Reverses the series, labels and series data arrays. @@ -532,9 +585,13 @@ var Chartist = { } else if (highLow.low < 0) { // If we have the same negative value for the bounds we set bounds.high to 0 highLow.high = 0; - } else { + } else if (highLow.high > 0) { // If we have the same positive value for the bounds we set bounds.low to 0 highLow.low = 0; + } else { + // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors + highLow.high = 1; + highLow.low = 0; } } @@ -1158,10 +1215,13 @@ var Chartist = { // This is necessary to treat "holes" in line charts var segments = splitIntoSegments(pathCoordinates, valueData); - // If the split resulted in more that one segment we need to interpolate each segment individually and join them - // afterwards together into a single path. - if(segments.length > 1) { - var paths = []; + if(!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return Chartist.Interpolation.none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; // For each segment we will recurse the cardinal function segments.forEach(function(segment) { paths.push(cardinal(segment.pathCoordinates, segment.valueData)); @@ -1677,16 +1737,6 @@ var Chartist = { (function(window, document, Chartist) { 'use strict'; - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; - - Chartist.xmlNs = { - qualifiedName: 'xmlns:ct', - prefix: 'ct', - uri: 'http://gionkunz.github.com/chartist-js/ct' - }; - /** * 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. * @@ -1703,11 +1753,13 @@ var Chartist = { if(name instanceof Element) { this._node = name; } else { - this._node = document.createElementNS(svgNs, name); + this._node = document.createElementNS(Chartist.namespaces.svg, name); // If this is an SVG element created then custom namespace if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + this.attr({ + 'xmlns:ct': Chartist.namespaces.ct + }); } } @@ -1733,7 +1785,7 @@ var Chartist = { * * @memberof Chartist.Svg * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @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. * @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. */ function attr(attributes, ns) { @@ -1751,8 +1803,9 @@ var Chartist = { return; } - if(ns) { - this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + if (key.indexOf(':') !== -1) { + var namespacedAttribute = key.split(':'); + this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]); } else { this._node.setAttribute(key, attributes[key]); } @@ -1843,7 +1896,7 @@ var Chartist = { } // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); + content.setAttribute('xmlns', Chartist.namespaces.xmlns); // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) @@ -1981,43 +2034,23 @@ var Chartist = { } /** - * "Save" way to get property value from svg BoundingBox. - * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node. - * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/) - * - * @memberof Chartist.Svg - * @param {SVGElement} node The svg node to - * @param {String} prop The property to fetch (ex.: height, width, ...) - * @returns {Number} The value of the given bbox property - */ - function getBBoxProperty(node, prop) { - try { - return node.getBBox()[prop]; - } catch(e) {} - - return 0; - } - - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element height using `getBoundingClientRect` * * @memberof Chartist.Svg * @return {Number} The elements height in pixels */ function height() { - return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight; + return this._node.getBoundingClientRect().height; } /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element width using `getBoundingClientRect` * * @memberof Chartist.Core * @return {Number} The elements width in pixels */ function width() { - return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth; + return this._node.getBoundingClientRect().width; } /** @@ -2725,7 +2758,7 @@ var Chartist = { } // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!labelValues[index] && labelValues[index] !== 0) { + if(!Chartist.isFalseyButZero(labelValues[index]) && !labelValues[index] === '') { return; } @@ -3042,6 +3075,7 @@ var Chartist = { * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: Chartist.getDataArray(this.data, options.reverseData, true) @@ -3084,9 +3118,9 @@ var Chartist = { // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -3136,11 +3170,9 @@ var Chartist = { x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { - return v; - }).join(','), - 'meta': pathElement.data.meta - }, Chartist.xmlNs.uri); + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), + 'ct:meta': pathElement.data.meta + }); this.eventEmitter.emit('draw', { type: 'point', @@ -3214,9 +3246,7 @@ var Chartist = { // and adding the created DOM elements to the correct series group var area = seriesElement.elem('path', { d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': data.normalized[seriesIndex] - }, Chartist.xmlNs.uri); + }, options.classNames.area, true); // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { @@ -3410,8 +3440,6 @@ var Chartist = { high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, - // Use only integer values (whole numbers) for the scale steps - onlyInteger: false, // 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} chartPadding: { top: 15, @@ -3454,6 +3482,7 @@ var Chartist = { * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { @@ -3476,15 +3505,15 @@ var Chartist = { var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); - if(options.stackBars) { + if(options.stackBars && data.normalized.length !== 0) { // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { return value; }).reduce(function(prev, curr) { return { - x: prev.x + curr.x || 0, - y: prev.y + curr.y || 0 + x: prev.x + (curr && curr.x) || 0, + y: prev.y + (curr && curr.y) || 0 }; }, {x: 0, y: 0}); }); @@ -3600,9 +3629,9 @@ var Chartist = { // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -3691,11 +3720,9 @@ var Chartist = { // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': [value.x, value.y].filter(function(v) { - return v; - }).join(','), - 'meta': Chartist.getMetaData(series, valueIndex) - }, Chartist.xmlNs.uri); + 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','), + 'ct:meta': Chartist.getMetaData(series, valueIndex) + }); this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', @@ -3826,7 +3853,9 @@ var Chartist = { // 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. labelDirection: 'neutral', // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. - reverseData: false + reverseData: false, + // If true empty values will be ignored to avoid drawing unncessary slices and labels + ignoreEmptyValues: false }; /** @@ -3857,6 +3886,7 @@ var Chartist = { * @param options */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var seriesGroups = [], labelsGroup, chartRect, @@ -3921,13 +3951,16 @@ var Chartist = { // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { + // If current value is zero and we are ignoring empty values then skip to next value + if (dataArray[i] === 0 && options.ignoreEmptyValues) continue; + var series = this.data.series[i]; seriesGroups[i] = this.svg.elem('g', null, null, true); // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[i].attr({ - 'series-name': series.name - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name + }); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -3936,13 +3969,17 @@ var Chartist = { ].join(' ')); var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + + // Use slight offset so there are no transparent hairline issues + var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; + if(endAngle - overlappigStartAngle >= 359.99) { + endAngle = overlappigStartAngle + 359.99; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); // 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 @@ -3963,9 +4000,9 @@ var Chartist = { // Adding the pie series value to the path pathElement.attr({ - 'value': dataArray[i], - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:value': dataArray[i], + 'ct:meta': Chartist.serialize(series.meta) + }); // If this is a donut, we add the stroke-width as style attribute if(options.donut) { @@ -3995,7 +4032,7 @@ var Chartist = { if(options.showLabel) { // Position at the labelRadius distance from center and between start and end angle var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { @@ -4017,7 +4054,7 @@ var Chartist = { } } - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; } diff --git a/dist/chartist.min.js b/dist/chartist.min.js index dfb9e726..049a22ef 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,10 @@ -/* Chartist.js 0.9.5 - * Copyright © 2015 Gion Kunz - * Free to use under the WTFPL license. - * http://www.wtfpl.net/ +/* Chartist.js 0.9.6 + * Copyright © 2016 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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.5"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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(h){var k=i.elem("path",{d:h.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:h.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:k})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p180,0,s.x,s.y);a.donut||u.line(n.x,n.y);var v=j[p].elem("path",{d:u.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(v.attr({value:l[p],meta:c.serialize(q.meta)},c.xmlNs.uri),a.donut&&v.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:v,path:u.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var w=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),x=a.labelInterpolationFnc(this.data.labels?this.data.labels[p]:l[p],p);if(x||0===x){var y=b.elem("text",{dx:w.x,dy:w.y,"text-anchor":d(n,w,a.labelDirection)},a.classNames.label).text(""+x);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:y,text:""+x,x:w.x,y:w.y})}}k=r}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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.6"};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){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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){if(a=a||{series:[],labels:[]},a.series=a.series||[],a.labels=a.labels||[],a.series.length>0&&0===a.labels.length){var b,d=c.getDataArray(a);b=d.every(function(a){return a instanceof Array})?Math.max.apply(null,d.map(function(a){return a.length})):d.length,a.labels=c.times(b).map(function(){return""})}return 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.isNum=function(a){return!isNaN(a)&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return isNaN(+a)?void 0:+a},c.getMultiValue=function(a,b){return c.isNum(a)?+a:a?a[b||"y"]||0:0},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){var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=c.orderOfMagnitude(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=c.projectLength(a,j.step,j),l=d>k,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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[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,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",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){this.data=c.normalizeData(this.data);var b,d={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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!==d.normalized.length){var i=c.serialMap(d.normalized,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})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":b.name,"ct:meta":c.serialize(b.meta)}),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNum).join(","),"ct:meta":c.getMetaData(b,k)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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){this.data=c.normalizeData(this.data);var b,e,f,h,i,j=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p=359.99&&(r=s+359.99);var t=c.polarToCartesian(n.x,n.y,f,s),u=c.polarToCartesian(n.x,n.y,f,r),v=new c.Svg.Path(!a.donut).move(u.x,u.y).arc(f,f,0,r-k>180,0,t.x,t.y);a.donut||v.line(n.x,n.y);var w=j[p].elem("path",{d:v.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(w.attr({"ct:value":l[p],"ct:meta":c.serialize(q.meta)}),a.donut&&w.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:w,path:v.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var x=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),y=a.labelInterpolationFnc(this.data.labels&&!c.isFalseyButZero(this.data.labels[p])?this.data.labels[p]:l[p],p);if(y||0===y){var z=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":d(n,x,a.labelDirection)},a.classNames.label).text(""+y);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:z,text:""+y,x:x.x,y:x.y})}}k=r}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}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index 2c87ca8c..cea4ae4c 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":";;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,UAAW,WACT,MAAQF,GAAe,SAAIC,MAED,gBAAZG,SAIhBC,OAAOD,QAAUH,IAEjBD,EAAe,SAAIC,KAErBK,KAAM,WAYR,GAAIC,IACFC,QAAS,QA0/HX,OAv/HC,UAAUC,EAAQC,EAAUH,GAC3B,YASAA,GAASI,KAAO,SAAUC,GACxB,MAAOA,IAUTL,EAASM,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAWtCL,EAASS,OAAS,SAAUC,GAC1BA,EAASA,KAET,IAAIC,GAAUC,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,EAWpD,OAVAL,GAAQM,QAAQ,SAASC,GACvB,IAAK,GAAIC,KAAQD,GACa,gBAAjBA,GAAOC,IAAuC,OAAjBD,EAAOC,IAAoBD,EAAOC,YAAiBP,OAGzFF,EAAOS,GAAQD,EAAOC,GAFtBT,EAAOS,GAAQnB,EAASS,UAAWC,EAAOS,GAAOD,EAAOC,MAOvDT,GAYTV,EAASoB,WAAa,SAASC,EAAKC,EAAQC,GAC1C,MAAOF,GAAIG,QAAQ,GAAIC,QAAOH,EAAQ,KAAMC,IAW9CvB,EAAS0B,WAAa,SAASC,EAAOC,GAKpC,MAJoB,gBAAVD,KACRA,GAAgBC,GAGXD,GAUT3B,EAAS6B,SAAW,SAASC,GAC3B,GAAqB,gBAAVA,GAAoB,CAC7B,GAAIC,GAAQ,kBAAoBC,KAAKF,EACrC,QACEH,OAASI,EAAM,GACfH,KAAMG,EAAM,IAAME,QAGtB,OAASN,MAAOG,IAUlB9B,EAASkC,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQhC,EAAS+B,cAAcC,IAUhEnC,EAASqC,MAAQ,SAASC,GACxB,MAAO1B,OAAM2B,MAAM,KAAM,GAAI3B,OAAM0B,KAWrCtC,EAASwC,IAAM,SAASC,EAAUC,GAChC,MAAOD,IAAYC,EAAUA,EAAU,IAUzC1C,EAAS2C,YAAc,SAASC,GAC9B,MAAO,UAASC,GACd,MAAOA,GAAMD,IAWjB5C,EAAS8C,OAAS,SAASC,GACzB,MAAO,UAASF,GACd,MAAOA,GAAME,IAYjB/C,EAASgD,UAAY,SAASC,EAAKC,GACjC,GAAIC,MACAb,EAASc,KAAKC,IAAId,MAAM,KAAMU,EAAIK,IAAI,SAASC,GAC7C,MAAOA,GAAEjB,SAWf,OARAtC,GAASqC,MAAMC,GAAQrB,QAAQ,SAASsC,EAAGC,GACzC,GAAIC,GAAOR,EAAIK,IAAI,SAASC,GAC1B,MAAOA,GAAEC,IAGXL,GAAOK,GAASN,EAAGX,MAAM,KAAMkB,KAG1BN,GAWTnD,EAAS0D,mBAAqB,SAAS/B,EAAOgC,GAC5C,GAAIC,GAAYR,KAAKS,IAAI,GAAIF,GAAU3D,EAAS4D,UAChD,OAAOR,MAAKU,MAAMnC,EAAQiC,GAAaA,GASzC5D,EAAS4D,UAAY,EAQrB5D,EAAS+D,aACPC,IAAK,QACLC,IAAK,OACLC,IAAK,OACLC,IAAK,SACLC,IAAM,UAWRpE,EAASqE,UAAY,SAASC,GAC5B,MAAY,QAATA,GAA0BrC,SAATqC,EACXA,GACiB,gBAATA,GACfA,EAAO,GAAGA,EACc,gBAATA,KACfA,EAAOC,KAAKC,WAAWF,KAAMA,KAGxBG,OAAOC,KAAK1E,EAAS+D,aAAaY,OAAO,SAASxB,EAAQyB,GAC/D,MAAO5E,GAASoB,WAAW+B,EAAQyB,EAAK5E,EAAS+D,YAAYa,KAC5DN,KAULtE,EAAS6E,YAAc,SAASP,GAC9B,GAAmB,gBAATA,GACR,MAAOA,EAGTA,GAAOG,OAAOC,KAAK1E,EAAS+D,aAAaY,OAAO,SAASxB,EAAQyB,GAC/D,MAAO5E,GAASoB,WAAW+B,EAAQnD,EAAS+D,YAAYa,GAAMA,IAC7DN,EAEH,KACEA,EAAOC,KAAKO,MAAMR,GAClBA,EAAqBrC,SAAdqC,EAAKA,KAAqBA,EAAKA,KAAOA,EAC7C,MAAMf,IAER,MAAOe,IAaTtE,EAAS+E,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIC,EAwBJ,OAtBAH,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAInBtE,MAAMC,UAAUC,MAAMC,KAAKiE,EAAUK,iBAAiB,QAAQC,OAAO,SAAkCF,GACrG,MAAOA,GAAIG,eAAe,gCAAiCvF,EAASwF,MAAMC,UACzExE,QAAQ,SAA+BmE,GACxCJ,EAAUU,YAAYN,KAIxBA,EAAM,GAAIpF,GAAS2F,IAAI,OAAOC,MAC5BX,MAAOA,EACPC,OAAQA,IACPW,SAASV,GAAWS,MACrBE,MAAO,UAAYb,EAAQ,aAAeC,EAAS,MAIrDF,EAAUe,YAAYX,EAAIY,OAEnBZ,GAUTpF,EAASiG,YAAc,SAAS3B,GAC9BA,EAAK4B,OAAOC,UACZ7B,EAAK8B,OAAOD,SACZ,KAAK,GAAIE,GAAI,EAAGA,EAAI/B,EAAK8B,OAAO9D,OAAQ+D,IACR,gBAApB/B,GAAK8B,OAAOC,IAA4CpE,SAAxBqC,EAAK8B,OAAOC,GAAG/B,KACvDA,EAAK8B,OAAOC,GAAG/B,KAAK6B,UACZ7B,EAAK8B,OAAOC,YAAczF,QAClC0D,EAAK8B,OAAOC,GAAGF,WAcrBnG,EAASsG,aAAe,SAAUhC,EAAM6B,EAASI,GAW/C,QAASC,GAAiB7E,GACxB,IAAG3B,EAASyG,gBAAgB9E,GAA5B,CAGO,IAAIA,EAAM2C,MAAQ3C,YAAkBf,OACzC,OAAQe,EAAM2C,MAAQ3C,GAAO2B,IAAIkD,EAC5B,IAAG7E,EAAM+E,eAAe,SAC7B,MAAOF,GAAiB7E,EAAMA,MAE9B,IAAG4E,EAAO,CACR,GAAII,KAcJ,OAToB,gBAAVJ,GACRI,EAAWJ,GAASvG,EAAS4G,qBAAqBjF,GAElDgF,EAAWE,EAAI7G,EAAS4G,qBAAqBjF,GAG/CgF,EAAWG,EAAInF,EAAM+E,eAAe,KAAO1G,EAAS4G,qBAAqBjF,EAAMmF,GAAKH,EAAWG,EAC/FH,EAAWE,EAAIlF,EAAM+E,eAAe,KAAO1G,EAAS4G,qBAAqBjF,EAAMkF,GAAKF,EAAWE,EAExFF,EAGP,MAAO3G,GAAS4G,qBAAqBjF,IAK3C,OAvCGwE,IAAY7B,EAAKyC,WAAaZ,GAAW7B,EAAKyC,YAC/C/G,EAASiG,YAAY3B,GACrBA,EAAKyC,UAAYzC,EAAKyC,UAqCjBzC,EAAK8B,OAAO9C,IAAIkD,IAWzBxG,EAASgH,iBAAmB,SAASC,EAASC,GAG5C,MAFAA,GAAWA,GAAY,EAEG,gBAAZD,IACZE,IAAKF,EACLG,MAAOH,EACPI,OAAQJ,EACRK,KAAML,IAENE,IAA4B,gBAAhBF,GAAQE,IAAmBF,EAAQE,IAAMD,EACrDE,MAAgC,gBAAlBH,GAAQG,MAAqBH,EAAQG,MAAQF,EAC3DG,OAAkC,gBAAnBJ,GAAQI,OAAsBJ,EAAQI,OAASH,EAC9DI,KAA8B,gBAAjBL,GAAQK,KAAoBL,EAAQK,KAAOJ,IAI5DlH,EAASuH,YAAc,SAASnB,EAAQ5C,GACtC,GAAI7B,GAAQyE,EAAO9B,KAAO8B,EAAO9B,KAAKd,GAAS4C,EAAO5C,EACtD,OAAO7B,GAAQ3B,EAASqE,UAAU1C,EAAM6F,MAAQvF,QAUlDjC,EAASyH,iBAAmB,SAAU9F,GACpC,MAAOyB,MAAKsE,MAAMtE,KAAKuE,IAAIvE,KAAKwE,IAAIjG,IAAUyB,KAAKyE,OAYrD7H,EAAS8H,cAAgB,SAAUC,EAAYzF,EAAQ0F,GACrD,MAAO1F,GAAS0F,EAAOC,MAAQF,GAWjC/H,EAASkI,mBAAqB,SAAU9C,EAAK+C,GAC3C,MAAO/E,MAAKC,KAAKrD,EAAS6B,SAASsG,EAAQjD,QAAQvD,OAASyD,EAAIF,WAAaiD,EAAQC,aAAajB,IAAOgB,EAAQC,aAAaf,QAAUc,EAAQE,MAAMC,OAAQ,IAYhKtI,EAASuI,WAAa,SAAUjE,EAAM6D,EAASK,GAY7C,QAASC,GAAiBnE,GACxB,GAAYrC,SAATqC,EAEI,GAAGA,YAAgB1D,OACxB,IAAK,GAAIyF,GAAI,EAAGA,EAAI/B,EAAKhC,OAAQ+D,IAC/BoC,EAAiBnE,EAAK+B,QAEnB,CACL,GAAI1E,GAAQ6G,GAAalE,EAAKkE,IAAclE,CAExCoE,IAAY/G,EAAQgH,EAAQC,OAC9BD,EAAQC,KAAOjH,GAGbkH,GAAWlH,EAAQgH,EAAQG,MAC7BH,EAAQG,IAAMnH,IAzBpBwG,EAAUnI,EAASS,UAAW0H,EAASK,EAAYL,EAAQ,OAASK,EAAUO,kBAE9E,IAAIJ,IACAC,KAAuB3G,SAAjBkG,EAAQS,MAAsBI,OAAOC,WAAad,EAAQS,KAChEE,IAAqB7G,SAAhBkG,EAAQW,IAAoBE,OAAOC,WAAad,EAAQW,KAE7DJ,EAA4BzG,SAAjBkG,EAAQS,KACnBC,EAA0B5G,SAAhBkG,EAAQW,GAmDtB,QA3BGJ,GAAYG,IACbJ,EAAiBnE,IAMf6D,EAAQe,gBAA6C,IAA3Bf,EAAQe,kBACpCP,EAAQC,KAAOxF,KAAKC,IAAI8E,EAAQe,eAAgBP,EAAQC,MACxDD,EAAQG,IAAM1F,KAAK+F,IAAIhB,EAAQe,eAAgBP,EAAQG,MAKrDH,EAAQC,MAAQD,EAAQG,MAEN,IAAhBH,EAAQG,IACVH,EAAQC,KAAO,EACND,EAAQG,IAAM,EAEvBH,EAAQC,KAAO,EAGfD,EAAQG,IAAM,GAIXH,GAUT3I,EAASoJ,MAAQ,SAASzH,GACxB,OAAQ0H,MAAM1H,IAAU2H,SAAS3H,IAUnC3B,EAASyG,gBAAkB,SAAS9E,GAClC,OAAQA,GAAmB,IAAVA,GAUnB3B,EAAS4G,qBAAuB,SAASjF,GACvC,MAAO0H,QAAO1H,GAASM,QAAaN,GAUtC3B,EAASuJ,cAAgB,SAAS5H,EAAO6G,GACvC,MAAGxI,GAASoJ,MAAMzH,IACRA,EACAA,EACDA,EAAM6G,GAAa,MAAQ,EAE3B,GAWXxI,EAASwJ,IAAM,SAAS3G,GAKtB,QAAS4G,GAAIC,EAAGC,GACd,MAAID,GAAIC,IAAM,EACLA,EAEAF,EAAIE,EAAGD,EAAIC,GAItB,QAASC,GAAE9C,GACT,MAAOA,GAAIA,EAAI,EAbjB,GAAW,IAARjE,EACD,MAAOA,EAeT,IAAoBgH,GAAhBC,EAAK,EAAGC,EAAK,CACjB,IAAIlH,EAAM,IAAM,EACd,MAAO,EAGT,GACEiH,GAAKF,EAAEE,GAAMjH,EACbkH,EAAKH,EAAEA,EAAEG,IAAOlH,EAChBgH,EAAUJ,EAAIrG,KAAKwE,IAAIkC,EAAKC,GAAKlH,SACd,IAAZgH,EAET,OAAOA,IAaT7J,EAASgK,UAAY,SAAUjC,EAAYY,EAASsB,EAAeC,GACjE,GAAI7D,GAEF8D,EACAC,EAFAC,EAAsB,EAGtBrC,GACEY,KAAMD,EAAQC,KACdE,IAAKH,EAAQG,IAGjBd,GAAOsC,WAAatC,EAAOY,KAAOZ,EAAOc,IACzCd,EAAOuC,IAAMvK,EAASyH,iBAAiBO,EAAOsC,YAC9CtC,EAAOwC,KAAOpH,KAAKS,IAAI,GAAImE,EAAOuC,KAClCvC,EAAOmB,IAAM/F,KAAKsE,MAAMM,EAAOc,IAAMd,EAAOwC,MAAQxC,EAAOwC,KAC3DxC,EAAO3E,IAAMD,KAAKqH,KAAKzC,EAAOY,KAAOZ,EAAOwC,MAAQxC,EAAOwC,KAC3DxC,EAAOC,MAAQD,EAAO3E,IAAM2E,EAAOmB,IACnCnB,EAAO0C,cAAgBtH,KAAKU,MAAMkE,EAAOC,MAAQD,EAAOwC,KAIxD,IAAIlI,GAAStC,EAAS8H,cAAcC,EAAYC,EAAOwC,KAAMxC,GACzD2C,EAAmBV,EAAT3H,EACVsI,EAAiBV,EAAclK,EAASwJ,IAAIxB,EAAOC,OAAS,CAGhE,IAAGiC,GAAelK,EAAS8H,cAAcC,EAAY,EAAGC,IAAWiC,EACjEjC,EAAOwC,KAAO,MACT,IAAGN,GAAeU,EAAiB5C,EAAOwC,MAAQxK,EAAS8H,cAAcC,EAAY6C,EAAgB5C,IAAWiC,EAIrHjC,EAAOwC,KAAOI,MAGd,QAAa,CACX,GAAID,GAAW3K,EAAS8H,cAAcC,EAAYC,EAAOwC,KAAMxC,IAAWiC,EACxEjC,EAAOwC,MAAQ,MACV,CAAA,GAAKG,KAAW3K,EAAS8H,cAAcC,EAAYC,EAAOwC,KAAO,EAAGxC,IAAWiC,GAOpF,KALA,IADAjC,EAAOwC,MAAQ,EACZN,GAAelC,EAAOwC,KAAO,IAAM,EAAG,CACvCxC,EAAOwC,MAAQ,CACf,QAMJ,GAAGH,IAAwB,IACzB,KAAM,IAAIQ,OAAM,sEAQtB,IAFAV,EAASnC,EAAOmB,IAChBiB,EAASpC,EAAO3E,IACV8G,EAASnC,EAAOwC,MAAQxC,EAAOc,KACnCqB,GAAUnC,EAAOwC,IAEnB,MAAMJ,EAASpC,EAAOwC,MAAQxC,EAAOY,MACnCwB,GAAUpC,EAAOwC,IAOnB,KALAxC,EAAOmB,IAAMgB,EACbnC,EAAO3E,IAAM+G,EACbpC,EAAOC,MAAQD,EAAO3E,IAAM2E,EAAOmB,IAEnCnB,EAAO8C,UACFzE,EAAI2B,EAAOmB,IAAK9C,GAAK2B,EAAO3E,IAAKgD,GAAK2B,EAAOwC,KAChDxC,EAAO8C,OAAOC,KAAK/K,EAAS0D,mBAAmB2C,GAGjD,OAAO2B,IAaThI,EAASgL,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAMhI,KAAKkI,GAAK,GAEvD,QACExE,EAAGmE,EAAWE,EAAS/H,KAAKmI,IAAIF,GAChCxE,EAAGqE,EAAWC,EAAS/H,KAAKoI,IAAIH,KAapCrL,EAASyL,gBAAkB,SAAUrG,EAAK+C,EAASuD,GACjD,GAAIC,MAAaxD,EAAQE,QAASF,EAAQyD,OACtCC,EAAcF,EAAUxD,EAAQyD,MAAMtD,OAAS,EAC/CwD,EAAcH,EAAUxD,EAAQE,MAAMC,OAAS,EAE/CrD,EAAQG,EAAIH,SAAWjF,EAAS6B,SAASsG,EAAQlD,OAAOtD,OAAS,EACjEuD,EAASE,EAAIF,UAAYlF,EAAS6B,SAASsG,EAAQjD,QAAQvD,OAAS,EACpEoK,EAAoB/L,EAASgH,iBAAiBmB,EAAQC,aAAcsD,EAGxEzG,GAAQ7B,KAAKC,IAAI4B,EAAO4G,EAAcE,EAAkBzE,KAAOyE,EAAkB3E,OACjFlC,EAAS9B,KAAKC,IAAI6B,EAAQ4G,EAAcC,EAAkB5E,IAAM4E,EAAkB1E,OAElF,IAAI2E,IACF/E,QAAS8E,EACT9G,MAAO,WACL,MAAOlF,MAAKgK,GAAKhK,KAAK+J,IAExB5E,OAAQ,WACN,MAAOnF,MAAKkM,GAAKlM,KAAKmM,IA2B1B,OAvBGP,IAC8B,UAA3BxD,EAAQE,MAAM8D,UAChBH,EAAUE,GAAKH,EAAkB5E,IAAM2E,EACvCE,EAAUC,GAAK7I,KAAKC,IAAI6B,EAAS6G,EAAkB1E,OAAQ2E,EAAUE,GAAK,KAE1EF,EAAUE,GAAKH,EAAkB5E,IACjC6E,EAAUC,GAAK7I,KAAKC,IAAI6B,EAAS6G,EAAkB1E,OAASyE,EAAaE,EAAUE,GAAK,IAG3D,UAA3B/D,EAAQyD,MAAMO,UAChBH,EAAUlC,GAAKiC,EAAkBzE,KAAOuE,EACxCG,EAAUjC,GAAK3G,KAAKC,IAAI4B,EAAQ8G,EAAkB3E,MAAO4E,EAAUlC,GAAK,KAExEkC,EAAUlC,GAAKiC,EAAkBzE,KACjC0E,EAAUjC,GAAK3G,KAAKC,IAAI4B,EAAQ8G,EAAkB3E,MAAQyE,EAAaG,EAAUlC,GAAK,MAGxFkC,EAAUlC,GAAKiC,EAAkBzE,KACjC0E,EAAUjC,GAAK3G,KAAKC,IAAI4B,EAAQ8G,EAAkB3E,MAAO4E,EAAUlC,GAAK,GACxEkC,EAAUE,GAAKH,EAAkB5E,IACjC6E,EAAUC,GAAK7I,KAAKC,IAAI6B,EAAS6G,EAAkB1E,OAAQ2E,EAAUE,GAAK,IAGrEF,GAgBThM,EAASoM,WAAa,SAASD,EAAU3I,EAAO6I,EAAM/D,EAAQhG,EAAQgK,EAAOC,EAASC,GACpF,GAAIC,KACJA,GAAeJ,EAAKK,MAAMC,IAAM,KAAOR,EACvCM,EAAeJ,EAAKK,MAAMC,IAAM,KAAOR,EACvCM,EAAeJ,EAAKO,aAAaD,IAAM,KAAOrE,EAC9CmE,EAAeJ,EAAKO,aAAaD,IAAM,KAAOrE,EAAShG,CAEvD,IAAIuK,GAAcP,EAAMQ,KAAK,OAAQL,EAAgBF,EAAQQ,KAAK,KAGlEP,GAAaQ,KAAK,OAChBhN,EAASS,QACPwM,KAAM,OACNZ,KAAMA,EACN7I,MAAOA,EACP8I,MAAOA,EACPY,QAASL,GACRJ,KAoBPzM,EAASmN,YAAc,SAAShB,EAAU7J,EAAQkB,EAAO0C,EAAQmG,EAAMe,EAAYC,EAAaf,EAAOC,EAASe,EAAkBd,GAChI,GAAIe,GACAd,IAOJ,IALAA,EAAeJ,EAAKK,MAAMC,KAAOR,EAAWkB,EAAYhB,EAAKK,MAAMC,KACnEF,EAAeJ,EAAKO,aAAaD,KAAOU,EAAYhB,EAAKO,aAAaD,KACtEF,EAAeJ,EAAKK,MAAMc,KAAOlL,EACjCmK,EAAeJ,EAAKO,aAAaY,KAAOJ,EAAa,GAElDE,EAAkB,CAGnB,GAAIG,GAAU,gBAAkBlB,EAAQQ,KAAK,KAAO,YAClDV,EAAKK,MAAMc,IAAM,KAAOpK,KAAKU,MAAM2I,EAAeJ,EAAKK,MAAMc,MAAQ,OACrEnB,EAAKO,aAAaY,IAAM,KAAOpK,KAAKU,MAAM2I,EAAeJ,EAAKO,aAAaY,MAAQ,OACnFtH,EAAO1C,GAAS,SAElB+J,GAAejB,EAAMoB,cAAcD,EAASzN,EAASS,QACnDqF,MAAO,sBACN2G,QAEHc,GAAejB,EAAMQ,KAAK,OAAQL,EAAgBF,EAAQQ,KAAK,MAAMY,KAAKzH,EAAO1C,GAGnFgJ,GAAaQ,KAAK,OAAQhN,EAASS,QACjCwM,KAAM,QACNZ,KAAMA,EACN7I,MAAOA,EACP8I,MAAOA,EACPY,QAASK,EACTI,KAAMzH,EAAO1C,IACZiJ,KAYLzM,EAAS4N,gBAAkB,SAASxH,EAAQ+B,EAASvD,GACnD,GAAGwB,EAAOyH,MAAQ1F,EAAQ/B,QAAU+B,EAAQ/B,OAAOA,EAAOyH,MAAO,CAC/D,GAAIC,GAAgB3F,EAAQ/B,OAAOA,EAAOyH,KAC1C,OAAOC,GAAcpH,eAAe9B,GAAOkJ,EAAclJ,GAAOuD,EAAQvD,GAExE,MAAOuD,GAAQvD,IAanB5E,EAAS+N,gBAAkB,SAAU5F,EAAS6F,EAAmBxB,GAM/D,QAASyB,GAAqBC,GAC5B,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiBpO,EAASS,UAAW4N,GAEjCL,EACF,IAAK3H,EAAI,EAAGA,EAAI2H,EAAkB1L,OAAQ+D,IAAK,CAC7C,GAAIiI,GAAMpO,EAAOqO,WAAWP,EAAkB3H,GAAG,GAC7CiI,GAAIE,UACNJ,EAAiBpO,EAASS,OAAO2N,EAAgBJ,EAAkB3H,GAAG,KAKzEmG,IAAiB0B,GAClB1B,EAAaQ,KAAK,kBAChBmB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoBzN,QAAQ,SAASqN,GACnCA,EAAIK,eAAeV,KA5BvB,GACEG,GAEA/H,EAHEgI,EAAcrO,EAASS,UAAW0H,GAEpCuG,IA8BF,KAAKxO,EAAOqO,WACV,KAAM,iEACD,IAAIP,EAET,IAAK3H,EAAI,EAAGA,EAAI2H,EAAkB1L,OAAQ+D,IAAK,CAC7C,GAAIiI,GAAMpO,EAAOqO,WAAWP,EAAkB3H,GAAG,GACjDiI,GAAIM,YAAYX,GAChBS,EAAoB3D,KAAKuD,GAM7B,MAFAL,IAAqB,IAGnBQ,0BAA2BA,EAC3BI,kBAAmB,WACjB,MAAO7O,GAASS,UAAW2N,OAKjClO,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEAA,GAAS8O,iBAmBT9O,EAAS8O,cAAcC,KAAO,SAAS5G,GACrC,GAAI6G,IACFC,WAAW,EAGb,OADA9G,GAAUnI,EAASS,UAAWuO,EAAgB7G,GACvC,SAAc+G,EAAiBC,GAIpC,IAAI,GAHAC,GAAO,GAAIpP,GAAS2F,IAAI0J,KACxBC,GAAO,EAEHjJ,EAAI,EAAGA,EAAI6I,EAAgB5M,OAAQ+D,GAAK,EAAG,CACjD,GAAIkJ,GAAQL,EAAgB7I,GACxBmJ,EAAQN,EAAgB7I,EAAI,GAC5BoJ,EAAWN,EAAU9I,EAAI,EAEPpE,UAAnBwN,EAAS9N,OAEP2N,EACDF,EAAKM,KAAKH,EAAOC,GAAO,EAAOC,GAE/BL,EAAKO,KAAKJ,EAAOC,GAAO,EAAOC,GAGjCH,GAAO,GACEnH,EAAQ8G,YACjBK,GAAO,GAIX,MAAOF,KA2BXpP,EAAS8O,cAAcc,OAAS,SAASzH,GACvC,GAAI6G,IACFnF,QAAS,EACToF,WAAW,EAEb9G,GAAUnI,EAASS,UAAWuO,EAAgB7G,EAE9C,IAAI0H,GAAI,EAAIzM,KAAKC,IAAI,EAAG8E,EAAQ0B,QAEhC,OAAO,UAAgBqF,EAAiBC,GAItC,IAAI,GAFAW,GAAOC,EAAOC,EADdZ,EAAO,GAAIpP,GAAS2F,IAAI0J,KAGpBhJ,EAAI,EAAGA,EAAI6I,EAAgB5M,OAAQ+D,GAAK,EAAG,CACjD,GAAIkJ,GAAQL,EAAgB7I,GACxBmJ,EAAQN,EAAgB7I,EAAI,GAC5B/D,GAAUiN,EAAQO,GAASD,EAC3BJ,EAAWN,EAAU9I,EAAI,EAEPpE,UAAnBwN,EAAS9N,OAEMM,SAAb+N,EACDZ,EAAKM,KAAKH,EAAOC,GAAO,EAAOC,GAE/BL,EAAKa,MACHH,EAAQxN,EACRyN,EACAR,EAAQjN,EACRkN,EACAD,EACAC,GACA,EACAC,GAIJK,EAAQP,EACRQ,EAAQP,EACRQ,EAAWP,GACFtH,EAAQ8G,YACjBa,EAAQP,EAAQS,EAAW/N,QAI/B,MAAOmN,KA0BXpP,EAAS8O,cAAcoB,SAAW,SAAS/H,GAczC,QAASgI,GAAkBjB,EAAiBC,GAI1C,IAAI,GAHAiB,MACAd,GAAO,EAEHjJ,EAAI,EAAGA,EAAI6I,EAAgB5M,OAAQ+D,GAAK,EAEhBpE,SAA3BkN,EAAU9I,EAAI,GAAG1E,MACdwG,EAAQ8G,YACVK,GAAO,IAINA,IACDc,EAASrF,MACPmE,mBACAC,eAGFG,GAAO,GAITc,EAASA,EAAS9N,OAAS,GAAG4M,gBAAgBnE,KAAKmE,EAAgB7I,GAAI6I,EAAgB7I,EAAI,IAC3F+J,EAASA,EAAS9N,OAAS,GAAG6M,UAAUpE,KAAKoE,EAAU9I,EAAI,IAI/D,OAAO+J,GAxCT,GAAIpB,IACFqB,QAAS,EACTpB,WAAW,EAGb9G,GAAUnI,EAASS,UAAWuO,EAAgB7G,EAE9C,IAAImI,GAAIlN,KAAK+F,IAAI,EAAG/F,KAAKC,IAAI,EAAG8E,EAAQkI,UACtCE,EAAI,EAAID,CAmCV,OAAO,SAASJ,GAAShB,EAAiBC,GAGxC,GAAIiB,GAAWD,EAAkBjB,EAAiBC,EAIlD,IAAGiB,EAAS9N,OAAS,EAAG,CACtB,GAAIkO,KAMJ,OAJAJ,GAASnP,QAAQ,SAASwP,GACxBD,EAAMzF,KAAKmF,EAASO,EAAQvB,gBAAiBuB,EAAQtB,cAGhDnP,EAAS2F,IAAI0J,KAAKtC,KAAKyD,GAQ9B,GAJAtB,EAAkBkB,EAAS,GAAGlB,gBAC9BC,EAAYiB,EAAS,GAAGjB,UAGrBD,EAAgB5M,QAAU,EAC3B,MAAOtC,GAAS8O,cAAcC,OAAOG,EAAiBC,EAMxD,KAAK,GAFHuB,GADEtB,GAAO,GAAIpP,GAAS2F,IAAI0J,MAAOK,KAAKR,EAAgB,GAAIA,EAAgB,IAAI,EAAOC,EAAU,IAGxF9I,EAAI,EAAGsK,EAAOzB,EAAgB5M,OAAQqO,EAAO,GAAKD,EAAIrK,EAAGA,GAAK,EAAG,CACxE,GAAIqD,KACD5C,GAAIoI,EAAgB7I,EAAI,GAAIQ,GAAIqI,EAAgB7I,EAAI,KACpDS,GAAIoI,EAAgB7I,GAAIQ,GAAIqI,EAAgB7I,EAAI,KAChDS,GAAIoI,EAAgB7I,EAAI,GAAIQ,GAAIqI,EAAgB7I,EAAI,KACpDS,GAAIoI,EAAgB7I,EAAI,GAAIQ,GAAIqI,EAAgB7I,EAAI,IAEnDqK,GACGrK,EAEMsK,EAAO,IAAMtK,EACtBqD,EAAE,IAAM5C,GAAIoI,EAAgB,GAAIrI,GAAIqI,EAAgB,IAC3CyB,EAAO,IAAMtK,IACtBqD,EAAE,IAAM5C,GAAIoI,EAAgB,GAAIrI,GAAIqI,EAAgB,IACpDxF,EAAE,IAAM5C,GAAIoI,EAAgB,GAAIrI,GAAIqI,EAAgB,KALpDxF,EAAE,IAAM5C,GAAIoI,EAAgByB,EAAO,GAAI9J,GAAIqI,EAAgByB,EAAO,IAQhEA,EAAO,IAAMtK,EACfqD,EAAE,GAAKA,EAAE,GACCrD,IACVqD,EAAE,IAAM5C,GAAIoI,EAAgB7I,GAAIQ,GAAIqI,EAAgB7I,EAAI,KAI5D+I,EAAKa,MACFK,IAAM5G,EAAE,GAAG5C,EAAI,EAAI4C,EAAE,GAAG5C,EAAI4C,EAAE,GAAG5C,GAAK,EAAMyJ,EAAI7G,EAAE,GAAG5C,EACrDwJ,IAAM5G,EAAE,GAAG7C,EAAI,EAAI6C,EAAE,GAAG7C,EAAI6C,EAAE,GAAG7C,GAAK,EAAM0J,EAAI7G,EAAE,GAAG7C,EACrDyJ,GAAK5G,EAAE,GAAG5C,EAAI,EAAI4C,EAAE,GAAG5C,EAAI4C,EAAE,GAAG5C,GAAK,EAAMyJ,EAAI7G,EAAE,GAAG5C,EACpDwJ,GAAK5G,EAAE,GAAG7C,EAAI,EAAI6C,EAAE,GAAG7C,EAAI6C,EAAE,GAAG7C,GAAK,EAAM0J,EAAI7G,EAAE,GAAG7C,EACrD6C,EAAE,GAAG5C,EACL4C,EAAE,GAAG7C,GACL,EACAsI,GAAW9I,EAAI,GAAK,IAIxB,MAAO+I,KAyBbpP,EAAS8O,cAActE,KAAO,SAASrC,GACrC,GAAI6G,IACF4B,UAAU,EACV3B,WAAW,EAKb,OAFA9G,GAAUnI,EAASS,UAAWuO,EAAgB7G,GAEvC,SAAc+G,EAAiBC,GAKpC,IAAK,GAFDW,GAAOC,EAAOC,EAFdZ,EAAO,GAAIpP,GAAS2F,IAAI0J,KAInBhJ,EAAI,EAAGA,EAAI6I,EAAgB5M,OAAQ+D,GAAK,EAAG,CAClD,GAAIkJ,GAAQL,EAAgB7I,GACxBmJ,EAAQN,EAAgB7I,EAAI,GAC5BoJ,EAAWN,EAAU9I,EAAI,EAGPpE,UAAnBwN,EAAS9N,OACMM,SAAb+N,EACDZ,EAAKM,KAAKH,EAAOC,GAAO,EAAOC,IAE5BtH,EAAQyI,SAETxB,EAAKO,KAAKJ,EAAOQ,GAAO,EAAOC,GAG/BZ,EAAKO,KAAKG,EAAON,GAAO,EAAOC,GAGjCL,EAAKO,KAAKJ,EAAOC,GAAO,EAAOC,IAGjCK,EAAQP,EACRQ,EAAQP,EACRQ,EAAWP,GACFtH,EAAQ8G,YACjBa,EAAQC,EAAQC,EAAW/N,QAI/B,MAAOmN,MAIXlP,OAAQC,SAAUH,GAOnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAAS6Q,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAOhG,KAAKiG,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAOzO,cACV2O,GAASF,UAIXE,GAASF,IAYtB,QAAS/D,GAAK+D,EAAOzM,GAEhB2M,EAASF,IACVE,EAASF,GAAO9P,QAAQ,SAAS+P,GAC/BA,EAAQ1M,KAKT2M,EAAS,MACVA,EAAS,KAAKhQ,QAAQ,SAASoQ,GAC7BA,EAAYN,EAAOzM,KAvDzB,GAAI2M,KA4DJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpBlE,KAAMA,KAIV9M,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAASsR,GAAYC,GACnB,GAAItO,KACJ,IAAIsO,EAAKjP,OACP,IAAK,GAAI+D,GAAI,EAAGA,EAAIkL,EAAKjP,OAAQ+D,IAC/BpD,EAAI8H,KAAKwG,EAAKlL,GAGlB,OAAOpD,GA4CT,QAASxC,GAAO+Q,EAAYC,GAC1B,GAAIC,GAAaD,GAAsB1R,KAAKc,WAAab,EAAS2R,MAC9DC,EAAQnN,OAAOoN,OAAOH,EAE1B1R,GAAS2R,MAAMG,iBAAiBF,EAAOJ,EAEvC,IAAIO,GAAS,WACX,GACEC,GADEC,EAAKL,EAAMM,aAAe,YAU9B,OALAF,GAAWjS,OAASC,EAAWyE,OAAOoN,OAAOD,GAAS7R,KACtDkS,EAAG1P,MAAMyP,EAAUpR,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,IAIlDgR,EAOT,OAJAD,GAAOlR,UAAY+Q,EACnBG,EAAAA,SAAeL,EACfK,EAAOtR,OAASV,KAAKU,OAEdsR,EAIT,QAASD,KACP,GAAIrO,GAAO6N,EAAYtQ,WACnBN,EAAS+C,EAAK,EAYlB,OAVAA,GAAK0N,OAAO,EAAG1N,EAAKnB,OAAS,GAAGrB,QAAQ,SAAUC,GAChDuD,OAAO0N,oBAAoBjR,GAAQD,QAAQ,SAAUmR,SAE5C1R,GAAO0R,GAEd3N,OAAO4N,eAAe3R,EAAQ0R,EAC5B3N,OAAO6N,yBAAyBpR,EAAQkR,QAIvC1R,EAGTV,EAAS2R,OACPlR,OAAQA,EACRqR,iBAAkBA,IAGpB5R,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAgBA,SAASuS,GAAOjO,EAAM6D,EAASqK,GA2B7B,MA1BGlO,KACDvE,KAAKuE,KAAOA,EAEZvE,KAAKyM,aAAaQ,KAAK,QACrBC,KAAM,SACN3I,KAAMvE,KAAKuE,QAIZ6D,IACDpI,KAAKoI,QAAUnI,EAASS,UAAW+R,EAAWzS,KAAKoI,QAAUpI,KAAKiP,eAAgB7G,GAI9EpI,KAAK0S,sBACP1S,KAAKgO,gBAAgBU,4BACrB1O,KAAKgO,gBAAkB/N,EAAS+N,gBAAgBhO,KAAKoI,QAASpI,KAAKiO,kBAAmBjO,KAAKyM,gBAK3FzM,KAAK0S,qBACP1S,KAAK2S,YAAY3S,KAAKgO,gBAAgBc,qBAIjC9O,KAQT,QAAS4S,KAUP,MAPI5S,MAAK0S,oBAIPvS,EAAO0S,aAAa7S,KAAK0S,sBAHzBvS,EAAO2S,oBAAoB,SAAU9S,KAAK+S,gBAC1C/S,KAAKgO,gBAAgBU,6BAKhB1O,KAUT,QAASgT,GAAGhC,EAAOC,GAEjB,MADAjR,MAAKyM,aAAasE,gBAAgBC,EAAOC,GAClCjR,KAUT,QAASiT,GAAIjC,EAAOC,GAElB,MADAjR,MAAKyM,aAAa0E,mBAAmBH,EAAOC,GACrCjR,KAGT,QAASkT,KAEP/S,EAAOgT,iBAAiB,SAAUnT,KAAK+S,gBAIvC/S,KAAKgO,gBAAkB/N,EAAS+N,gBAAgBhO,KAAKoI,QAASpI,KAAKiO,kBAAmBjO,KAAKyM,cAE3FzM,KAAKyM,aAAasE,gBAAgB,iBAAkB,WAClD/Q,KAAKwS,UACLY,KAAKpT,OAIJA,KAAKoI,QAAQiL,SACdrT,KAAKoI,QAAQiL,QAAQnS,QAAQ,SAASoS,GACjCA,YAAkBzS,OACnByS,EAAO,GAAGtT,KAAMsT,EAAO,IAEvBA,EAAOtT,OAEToT,KAAKpT,OAITA,KAAKyM,aAAaQ,KAAK,QACrBC,KAAM,UACN3I,KAAMvE,KAAKuE,OAIbvE,KAAK2S,YAAY3S,KAAKgO,gBAAgBc,qBAItC9O,KAAK0S,oBAAsBxQ,OAa7B,QAASqR,GAAKnR,EAAOmC,EAAM0K,EAAgB7G,EAAS6F,GAClDjO,KAAKiF,UAAYhF,EAASkC,cAAcC,GACxCpC,KAAKuE,KAAOA,EACZvE,KAAKiP,eAAiBA,EACtBjP,KAAKoI,QAAUA,EACfpI,KAAKiO,kBAAoBA,EACzBjO,KAAKyM,aAAexM,EAAS6Q,eAC7B9Q,KAAKwT,sBAAwBvT,EAAS2F,IAAI6N,YAAY,iBACtDzT,KAAK0T,mBAAqBzT,EAAS2F,IAAI6N,YAAY,4BACnDzT,KAAK+S,eAAiB,WACpB/S,KAAKwS,UACLY,KAAKpT,MAEJA,KAAKiF,YAEHjF,KAAKiF,UAAU0O,cAChB3T,KAAKiF,UAAU0O,aAAaf,SAG9B5S,KAAKiF,UAAU0O,aAAe3T,MAKhCA,KAAK0S,oBAAsBkB,WAAWV,EAAWE,KAAKpT,MAAO,GAI/DC,EAASsT,KAAOtT,EAAS2R,MAAMlR,QAC7ByR,YAAaoB,EACbvF,gBAAiB9L,OACjB+C,UAAW/C,OACXmD,IAAKnD,OACLuK,aAAcvK,OACdyQ,YAAa,WACX,KAAM,IAAI7H,OAAM,2CAElB0H,OAAQA,EACRI,OAAQA,EACRI,GAAIA,EACJC,IAAKA,EACL/S,QAASD,EAASC,QAClBsT,uBAAuB,KAGzBrT,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAuBA,SAAS2F,GAAIkI,EAAM+F,EAAYzO,EAAW0O,EAAQC,GAE7CjG,YAAgBkG,SACjBhU,KAAKiG,MAAQ6H,GAEb9N,KAAKiG,MAAQ7F,EAAS6T,gBAAgBC,EAAOpG,GAGjC,QAATA,GACD9N,KAAKiG,MAAMkO,eAAe1O,EAAOxF,EAASwF,MAAM2O,cAAenU,EAASwF,MAAM4O,MAI/ER,GACD7T,KAAK6F,KAAKgO,GAGTzO,GACDpF,KAAK8F,SAASV,GAGb0O,IACGC,GAAeD,EAAO7N,MAAMqO,WAC9BR,EAAO7N,MAAMsO,aAAavU,KAAKiG,MAAO6N,EAAO7N,MAAMqO,YAEnDR,EAAO7N,MAAMD,YAAYhG,KAAKiG,QAapC,QAASJ,GAAKgO,EAAYW,GACxB,MAAyB,gBAAfX,GACLW,EACMxU,KAAKiG,MAAMT,eAAegP,EAAIX,GAE9B7T,KAAKiG,MAAMwO,aAAaZ,IAInCnP,OAAOC,KAAKkP,GAAY3S,QAAQ,SAAS2D,GAEhB3C,SAApB2R,EAAWhP,KAIX2P,EACDxU,KAAKiG,MAAMkO,eAAeK,GAAKvU,EAASwF,MAAMC,OAAQ,IAAKb,GAAKmI,KAAK,IAAK6G,EAAWhP,IAErF7E,KAAKiG,MAAMyO,aAAa7P,EAAKgP,EAAWhP,MAE1CuO,KAAKpT,OAEAA,MAaT,QAAS+M,GAAKe,EAAM+F,EAAYzO,EAAW2O,GACzC,MAAO,IAAI9T,GAAS2F,IAAIkI,EAAM+F,EAAYzO,EAAWpF,KAAM+T,GAS7D,QAASD,KACP,MAAO9T,MAAKiG,MAAM0O,qBAAsBC,YAAa,GAAI3U,GAAS2F,IAAI5F,KAAKiG,MAAM0O,YAAc,KASjG,QAASjV,KAEP,IADA,GAAImV,GAAO7U,KAAKiG,MACQ,QAAlB4O,EAAKC,UACTD,EAAOA,EAAKF,UAEd,OAAO,IAAI1U,GAAS2F,IAAIiP,GAU1B,QAAS1S,GAAc4S,GACrB,GAAIC,GAAYhV,KAAKiG,MAAM9D,cAAc4S,EACzC,OAAOC,GAAY,GAAI/U,GAAS2F,IAAIoP,GAAa,KAUnD,QAAS1P,GAAiByP,GACxB,GAAIE,GAAajV,KAAKiG,MAAMX,iBAAiByP,EAC7C,OAAOE,GAAW1S,OAAS,GAAItC,GAAS2F,IAAIsP,KAAKD,GAAc,KAajE,QAAStH,GAAcD,EAASmG,EAAYzO,EAAW2O,GAGrD,GAAsB,gBAAZrG,GAAsB,CAC9B,GAAIzI,GAAY7E,EAAS+U,cAAc,MACvClQ,GAAUmQ,UAAY1H,EACtBA,EAAUzI,EAAUqP,WAItB5G,EAAQgH,aAAa,QAASW,EAI9B,IAAIC,GAAQtV,KAAK+M,KAAK,gBAAiB8G,EAAYzO,EAAW2O,EAK9D,OAFAuB,GAAMrP,MAAMD,YAAY0H,GAEjB4H,EAUT,QAAS1H,GAAK2C,GAEZ,MADAvQ,MAAKiG,MAAMD,YAAY5F,EAASmV,eAAehF,IACxCvQ,KAST,QAASwV,KACP,KAAOxV,KAAKiG,MAAMqO,YAChBtU,KAAKiG,MAAMN,YAAY3F,KAAKiG,MAAMqO,WAGpC,OAAOtU,MAST,QAASyV,KAEP,MADAzV,MAAKiG,MAAM0O,WAAWhP,YAAY3F,KAAKiG,OAChCjG,KAAK8T,SAUd,QAASrS,GAAQiU,GAEf,MADA1V,MAAKiG,MAAM0O,WAAWgB,aAAaD,EAAWzP,MAAOjG,KAAKiG,OACnDyP,EAWT,QAASE,GAAOzI,EAAS4G,GAOvB,MANGA,IAAe/T,KAAKiG,MAAMqO,WAC3BtU,KAAKiG,MAAMsO,aAAapH,EAAQlH,MAAOjG,KAAKiG,MAAMqO,YAElDtU,KAAKiG,MAAMD,YAAYmH,EAAQlH,OAG1BjG,KAST,QAASwM,KACP,MAAOxM,MAAKiG,MAAMwO,aAAa,SAAWzU,KAAKiG,MAAMwO,aAAa,SAASoB,OAAOC,MAAM,UAU1F,QAAShQ,GAASiQ,GAShB,MARA/V,MAAKiG,MAAMyO,aAAa,QACtB1U,KAAKwM,QAAQxM,KAAKiG,OACf+P,OAAOD,EAAMF,OAAOC,MAAM,QAC1BvQ,OAAO,SAASwH,EAAMH,EAAKqJ,GAC1B,MAAOA,GAAK5E,QAAQtE,KAAUH,IAC7BI,KAAK,MAGLhN,KAUT,QAASkW,GAAYH,GACnB,GAAII,GAAiBJ,EAAMF,OAAOC,MAAM,MAMxC,OAJA9V,MAAKiG,MAAMyO,aAAa,QAAS1U,KAAKwM,QAAQxM,KAAKiG,OAAOV,OAAO,SAASuI,GACxE,MAAwC,KAAjCqI,EAAe9E,QAAQvD,KAC7Bd,KAAK,MAEDhN,KAST,QAASoW,KAGP,MAFApW,MAAKiG,MAAMyO,aAAa,QAAS,IAE1B1U,KAaT,QAASqW,GAAgBxB,EAAMzT,GAC7B,IACE,MAAOyT,GAAKyB,UAAUlV,GACtB,MAAMoC,IAER,MAAO,GAUT,QAAS2B,KACP,MAAOnF,MAAKiG,MAAMsQ,cAAgBlT,KAAKU,MAAMsS,EAAgBrW,KAAKiG,MAAO,YAAcjG,KAAKiG,MAAM0O,WAAW4B,aAU/G,QAASrR,KACP,MAAOlF,MAAKiG,MAAMuQ,aAAenT,KAAKU,MAAMsS,EAAgBrW,KAAKiG,MAAO,WAAajG,KAAKiG,MAAM0O,WAAW6B,YA4C7G,QAASC,GAAQC,EAAYC,EAAQlK,GA4GnC,MA3GcvK,UAAXyU,IACDA,GAAS,GAGXjS,OAAOC,KAAK+R,GAAYxV,QAAQ,SAAoC0V,GAElE,QAASC,GAAcC,EAAqBH,GAC1C,GACEF,GACAM,EACAC,EAHEC,IAODH,GAAoBE,SAErBA,EAASF,EAAoBE,iBAAkBnW,OAC7CiW,EAAoBE,OACpB/W,EAAS2F,IAAIsR,OAAOJ,EAAoBE,cACnCF,GAAoBE,QAI7BF,EAAoBK,MAAQlX,EAAS0B,WAAWmV,EAAoBK,MAAO,MAC3EL,EAAoBM,IAAMnX,EAAS0B,WAAWmV,EAAoBM,IAAK,MAEpEJ,IACDF,EAAoBO,SAAW,SAC/BP,EAAoBQ,WAAaN,EAAOhK,KAAK,KAC7C8J,EAAoBS,SAAW,OAI9BZ,IACDG,EAAoBU,KAAO,SAE3BP,EAAoBL,GAAaE,EAAoBW,KACrDzX,KAAK6F,KAAKoR,GAIVF,EAAU9W,EAAS6B,SAASgV,EAAoBK,OAAS,GAAGvV,MAC5DkV,EAAoBK,MAAQ,cAG9BV,EAAUzW,KAAK+M,KAAK,UAAW9M,EAASS,QACtCgX,cAAed,GACdE,IAEAH,GAED/C,WAAW,WAIT,IACE6C,EAAQxQ,MAAM0R,eACd,MAAMC,GAENX,EAAoBL,GAAaE,EAAoBe,GACrD7X,KAAK6F,KAAKoR,GAEVR,EAAQhB,WAEVrC,KAAKpT,MAAO+W,GAGbtK,GACDgK,EAAQxQ,MAAMkN,iBAAiB,aAAc,WAC3C1G,EAAaQ,KAAK,kBAChBE,QAASnN,KACTyW,QAASA,EAAQxQ,MACjB6R,OAAQhB,KAEV1D,KAAKpT,OAGTyW,EAAQxQ,MAAMkN,iBAAiB,WAAY,WACtC1G,GACDA,EAAaQ,KAAK,gBAChBE,QAASnN,KACTyW,QAASA,EAAQxQ,MACjB6R,OAAQhB,IAITH,IAEDM,EAAoBL,GAAaE,EAAoBe,GACrD7X,KAAK6F,KAAKoR,GAEVR,EAAQhB,WAEVrC,KAAKpT,OAIN0W,EAAWE,YAAsB/V,OAClC6V,EAAWE,GAAW1V,QAAQ,SAAS4V,GACrCD,EAAczD,KAAKpT,MAAM8W,GAAqB,IAC9C1D,KAAKpT,OAEP6W,EAAczD,KAAKpT,MAAM0W,EAAWE,GAAYD,IAGlDvD,KAAKpT,OAEAA,KA+ET,QAAS+X,GAAQC,GACf,GAAIxG,GAAOxR,IAEXA,MAAKiY,cACL,KAAI,GAAI3R,GAAI,EAAGA,EAAI0R,EAASzV,OAAQ+D,IAClCtG,KAAKiY,YAAYjN,KAAK,GAAI/K,GAAS2F,IAAIoS,EAAS1R,IAIlD5B,QAAOC,KAAK1E,EAAS2F,IAAI9E,WAAWyE,OAAO,SAAS2S,GAClD,MAQ4C,MARpC,cACJ,SACA,gBACA,mBACA,UACA,SACA,UACA,SACA,SAAS7G,QAAQ6G,KACpBhX,QAAQ,SAASgX,GAClB1G,EAAK0G,GAAqB,WACxB,GAAIxU,GAAO7C,MAAMC,UAAUC,MAAMC,KAAKC,UAAW,EAIjD,OAHAuQ,GAAKyG,YAAY/W,QAAQ,SAASiM,GAChClN,EAAS2F,IAAI9E,UAAUoX,GAAmB1V,MAAM2K,EAASzJ,KAEpD8N,KAplBb,GAAI0C,GAAQ,6BACVzO,EAAQ,gCACR4P,EAAU,8BAEZpV,GAASwF,OACP2O,cAAe,WACf1O,OAAQ,KACR2O,IAAK,6CAwePpU,EAAS2F,IAAM3F,EAAS2R,MAAMlR,QAC5ByR,YAAavM,EACbC,KAAMA,EACNkH,KAAMA,EACN+G,OAAQA,EACRpU,KAAMA,EACNyC,cAAeA,EACfmD,iBAAkBA,EAClBqI,cAAeA,EACfC,KAAMA,EACN4H,MAAOA,EACPC,OAAQA,EACRhU,QAASA,EACTmU,OAAQA,EACRpJ,QAASA,EACT1G,SAAUA,EACVoQ,YAAaA,EACbE,iBAAkBA,EAClBjR,OAAQA,EACRD,MAAOA,EACPuR,QAASA,IAUXxW,EAAS2F,IAAI6N,YAAc,SAAS0E,GAClC,MAAO/X,GAASgY,eAAeC,WAAW,sCAAwCF,EAAS,OAQ7F,IAAIG,IACFC,YAAa,IAAM,EAAG,KAAO,MAC7BC,aAAc,IAAM,KAAO,KAAO,GAClCC,eAAgB,KAAO,IAAM,IAAM,KACnCC,YAAa,IAAM,KAAO,IAAM,KAChCC,aAAc,IAAM,IAAM,IAAM,KAChCC,eAAgB,KAAO,IAAM,KAAO,MACpCC,aAAc,IAAM,KAAO,KAAO,KAClCC,cAAe,KAAO,IAAM,KAAO,GACnCC,gBAAiB,KAAO,KAAO,KAAO,GACtCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,KAAO,IAAM,IAAM,GAClCC,gBAAiB,IAAM,EAAG,KAAO,GACjCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,IAAM,EAAG,IAAM,GAC9BC,gBAAiB,IAAM,EAAG,IAAM,GAChCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,IAAM,EAAG,IAAM,GAC7BC,eAAgB,EAAG,EAAG,EAAG,GACzBC,YAAa,GAAK,IAAM,IAAM,MAC9BC,aAAc,KAAO,IAAM,KAAO,GAClCC,eAAgB,KAAO,KAAO,IAAM,KACpCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,KAAO,KAAO,IAAM,OAClCC,eAAgB,KAAO,IAAM,KAAO,MAGtC7Z,GAAS2F,IAAIsR,OAASoB,EAwCtBrY,EAAS2F,IAAIsP,KAAOjV,EAAS2R,MAAMlR,QACjCyR,YAAa4F,KAEf5X,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA0BA,SAASkN,GAAQ4M,EAASjC,EAAQkC,EAAcpN,EAAKqN,EAAU1V,GAC7D,GAAI2V,GAAcja,EAASS,QACzBqZ,QAASE,EAAWF,EAAQI,cAAgBJ,EAAQ/Q,eACnD8O,EAAQvT,GAASA,KAAMA,MAE1ByV,GAAa5I,OAAOxE,EAAK,EAAGsN,GAG9B,QAASE,GAAaJ,EAAc7W,GAClC6W,EAAa9Y,QAAQ,SAASgZ,EAAaG,GACzCC,EAAoBJ,EAAYH,QAAQI,eAAejZ,QAAQ,SAASqZ,EAAWC,GACjFrX,EAAG+W,EAAaK,EAAWF,EAAkBG,EAAYR,OAa/D,QAASS,GAAQC,EAAOtS,GACtBpI,KAAKga,gBACLha,KAAK4M,IAAM,EACX5M,KAAK0a,MAAQA,EACb1a,KAAKoI,QAAUnI,EAASS,UAAWuO,EAAgB7G,GAUrD,QAASgE,GAASQ,GAChB,MAAW1K,UAAR0K,GACD5M,KAAK4M,IAAMvJ,KAAKC,IAAI,EAAGD,KAAK+F,IAAIpJ,KAAKga,aAAazX,OAAQqK,IACnD5M,MAEAA,KAAK4M,IAWhB,QAAS6I,GAAOkF,GAEd,MADA3a,MAAKga,aAAa5I,OAAOpR,KAAK4M,IAAK+N,GAC5B3a,KAaT,QAAS2P,GAAK5I,EAAGD,EAAGmT,EAAU1V,GAK5B,MAJA4I,GAAQ,KACNpG,GAAIA,EACJD,GAAIA,GACH9G,KAAKga,aAAcha,KAAK4M,MAAOqN,EAAU1V,GACrCvE,KAaT,QAAS4P,GAAK7I,EAAGD,EAAGmT,EAAU1V,GAK5B,MAJA4I,GAAQ,KACNpG,GAAIA,EACJD,GAAIA,GACH9G,KAAKga,aAAcha,KAAK4M,MAAOqN,EAAU1V,GACrCvE,KAiBT,QAASkQ,GAAMnG,EAAImC,EAAIlC,EAAImC,EAAIpF,EAAGD,EAAGmT,EAAU1V,GAS7C,MARA4I,GAAQ,KACNpD,IAAKA,EACLmC,IAAKA,EACLlC,IAAKA,EACLmC,IAAKA,EACLpF,GAAIA,EACJD,GAAIA,GACH9G,KAAKga,aAAcha,KAAK4M,MAAOqN,EAAU1V,GACrCvE,KAkBT,QAAS4a,GAAIC,EAAIC,EAAIC,EAAKC,EAAKC,EAAIlU,EAAGD,EAAGmT,EAAU1V,GAUjD,MATA4I,GAAQ,KACN0N,IAAKA,EACLC,IAAKA,EACLC,KAAMA,EACNC,KAAMA,EACNC,IAAKA,EACLlU,GAAIA,EACJD,GAAIA,GACH9G,KAAKga,aAAcha,KAAK4M,MAAOqN,EAAU1V,GACrCvE,KAUT,QAAS+E,GAAMsK,GAEb,GAAI6L,GAAS7L,EAAK5N,QAAQ,qBAAsB,SAC7CA,QAAQ,qBAAsB,SAC9BqU,MAAM,UACNlR,OAAO,SAASxB,EAAQ+J,GAMvB,MALGA,GAAQnL,MAAM,aACfoB,EAAO4H,SAGT5H,EAAOA,EAAOb,OAAS,GAAGyI,KAAKmC,GACxB/J,MAIuC,OAA/C8X,EAAOA,EAAO3Y,OAAS,GAAG,GAAGyG,eAC9BkS,EAAOC,KAKT,IAAIC,GAAWF,EAAO3X,IAAI,SAAS8X,GAC/B,GAAItB,GAAUsB,EAAMC,QAClBC,EAAcjB,EAAoBP,EAAQI,cAE5C,OAAOla,GAASS,QACdqZ,QAASA,GACRwB,EAAY3W,OAAO,SAASxB,EAAQmX,EAAW9W,GAEhD,MADAL,GAAOmX,IAAcc,EAAM5X,GACpBL,UAKToY,GAAcxb,KAAK4M,IAAK,EAM5B,OALA/L,OAAMC,UAAUkK,KAAKxI,MAAMgZ,EAAYJ,GACvCva,MAAMC,UAAUsQ,OAAO5O,MAAMxC,KAAKga,aAAcwB,GAEhDxb,KAAK4M,KAAOwO,EAAS7Y,OAEdvC,KAST,QAASyE,KACP,GAAIgX,GAAqBpY,KAAKS,IAAI,GAAI9D,KAAKoI,QAAQsT,SAEnD,OAAO1b,MAAKga,aAAapV,OAAO,SAASyK,EAAM6K,GAC3C,GAAIpC,GAASwC,EAAoBJ,EAAYH,QAAQI,eAAe5W,IAAI,SAASgX,GAC/E,MAAOva,MAAKoI,QAAQsT,SACjBrY,KAAKU,MAAMmW,EAAYK,GAAakB,GAAsBA,EAC3DvB,EAAYK,IACdnH,KAAKpT,MAEP,OAAOqP,GAAO6K,EAAYH,QAAUjC,EAAO9K,KAAK,MAChDoG,KAAKpT,MAAO,KAAOA,KAAK0a,MAAQ,IAAM,IAW5C,QAASiB,GAAM5U,EAAGD,GAIhB,MAHAsT,GAAapa,KAAKga,aAAc,SAASE,EAAaK,GACpDL,EAAYK,IAA+B,MAAjBA,EAAU,GAAaxT,EAAID,IAEhD9G,KAWT,QAAS4b,GAAU7U,EAAGD,GAIpB,MAHAsT,GAAapa,KAAKga,aAAc,SAASE,EAAaK,GACpDL,EAAYK,IAA+B,MAAjBA,EAAU,GAAaxT,EAAID,IAEhD9G,KAeT,QAAS6b,GAAUC,GAOjB,MANA1B,GAAapa,KAAKga,aAAc,SAASE,EAAaK,EAAWF,EAAkBG,EAAYR,GAC7F,GAAI+B,GAAcD,EAAa5B,EAAaK,EAAWF,EAAkBG,EAAYR,IAClF+B,GAA+B,IAAhBA,KAChB7B,EAAYK,GAAawB,KAGtB/b,KAUT,QAASgc,GAAMtB,GACb,GAAIlK,GAAI,GAAIvQ,GAAS2F,IAAI0J,KAAKoL,GAAS1a,KAAK0a,MAM5C,OALAlK,GAAE5D,IAAM5M,KAAK4M,IACb4D,EAAEwJ,aAAeha,KAAKga,aAAajZ,QAAQwC,IAAI,SAAuB2W,GACpE,MAAOja,GAASS,UAAWwZ,KAE7B1J,EAAEpI,QAAUnI,EAASS,UAAWV,KAAKoI,SAC9BoI,EAUT,QAASyL,GAAelC,GACtB,GAAIjE,IACF,GAAI7V,GAAS2F,IAAI0J,KAWnB,OARAtP,MAAKga,aAAa9Y,QAAQ,SAASgZ,GAC9BA,EAAYH,UAAYA,EAAQ/Q,eAAiE,IAAhD8M,EAAMA,EAAMvT,OAAS,GAAGyX,aAAazX,QACvFuT,EAAM9K,KAAK,GAAI/K,GAAS2F,IAAI0J,MAG9BwG,EAAMA,EAAMvT,OAAS,GAAGyX,aAAahP,KAAKkP,KAGrCpE,EAaT,QAAS9I,GAAKyD,EAAOiK,EAAOtS,GAE1B,IAAI,GADA8T,GAAa,GAAIjc,GAAS2F,IAAI0J,KAAKoL,EAAOtS,GACtC9B,EAAI,EAAGA,EAAImK,EAAMlO,OAAQ+D,IAE/B,IAAI,GADA+I,GAAOoB,EAAMnK,GACT6V,EAAI,EAAGA,EAAI9M,EAAK2K,aAAazX,OAAQ4Z,IAC3CD,EAAWlC,aAAahP,KAAKqE,EAAK2K,aAAamC,GAGnD,OAAOD,GA3VT,GAAI5B,IACF8B,GAAI,IAAK,KACTC,GAAI,IAAK,KACT7L,GAAI,KAAM,KAAM,KAAM,KAAM,IAAK,KACjC8L,GAAI,KAAM,KAAM,MAAO,MAAO,KAAM,IAAK,MASvCrN,GAEFyM,SAAU,EA+UZzb,GAAS2F,IAAI0J,KAAOrP,EAAS2R,MAAMlR,QACjCyR,YAAasI,EACbrO,SAAUA,EACVqJ,OAAQA,EACR9F,KAAMA,EACNC,KAAMA,EACNM,MAAOA,EACP0K,IAAKA,EACLe,MAAOA,EACPC,UAAWA,EACXC,UAAWA,EACX9W,MAAOA,EACPN,UAAWA,EACXuX,MAAOA,EACPC,eAAgBA,IAGlBhc,EAAS2F,IAAI0J,KAAKgL,oBAAsBA,EACxCra,EAAS2F,IAAI0J,KAAKtC,KAAOA,GACzB7M,OAAQC,SAAUH,GAEnB,SAAUE,EAAQC,EAAUH,GAC3B,YAqBA,SAASsc,GAAK5P,EAAOV,EAAWuQ,EAAOpU,GACrCpI,KAAK2M,MAAQA,EACb3M,KAAK6M,aAAeF,IAAU8P,EAAU1V,EAAI0V,EAAU3V,EAAI2V,EAAU1V,EACpE/G,KAAKiM,UAAYA,EACjBjM,KAAKgI,WAAaiE,EAAUU,EAAM+P,SAAWzQ,EAAUU,EAAMgQ,WAC7D3c,KAAK4c,WAAa3Q,EAAUU,EAAMkQ,YAClC7c,KAAKwc,MAAQA,EACbxc,KAAKoI,QAAUA,EAGjB,QAAS0U,GAAoBC,EAAWC,EAAYzP,EAAkB0P,EAAcxQ,GAClF,GAAIyQ,GAAcD,EAAa,OAASjd,KAAK2M,MAAMC,IAAI5D,eACnDmU,EAAkBnd,KAAKwc,MAAMjZ,IAAIvD,KAAKod,aAAahK,KAAKpT,OACxDqd,EAAcrd,KAAKwc,MAAMjZ,IAAI2Z,EAAYI,sBAE7CH,GAAgBjc,QAAQ,SAASqc,EAAgB9Z,GAC/C,GAOI+Z,GAPAlQ,GACFvG,EAAG,EACHD,EAAG,EAQH0W,GAFCL,EAAgB1Z,EAAQ,GAEX0Z,EAAgB1Z,EAAQ,GAAK8Z,EAK7Bla,KAAKC,IAAItD,KAAKgI,WAAauV,EAAgB,KAIvDF,EAAY5Z,IAAiC,IAAvB4Z,EAAY5Z,MAMhB,MAAnBzD,KAAK2M,MAAMC,KACZ2Q,EAAiBvd,KAAKiM,UAAUlC,GAAKwT,EACrCjQ,EAAYvG,EAAIkW,EAAa3U,MAAMgF,YAAYvG,EAIZ,UAAhCkW,EAAa3U,MAAM8D,SACpBkB,EAAYxG,EAAI9G,KAAKiM,UAAU/E,QAAQE,IAAM6V,EAAa3U,MAAMgF,YAAYxG,GAAKyG,EAAmB,EAAI,IAExGD,EAAYxG,EAAI9G,KAAKiM,UAAUC,GAAK+Q,EAAa3U,MAAMgF,YAAYxG,GAAKyG,EAAmB,EAAI,MAGjGgQ,EAAiBvd,KAAKiM,UAAUC,GAAKqR,EACrCjQ,EAAYxG,EAAImW,EAAapR,MAAMyB,YAAYxG,GAAKyG,EAAmBiQ,EAAc,GAIlD,UAAhCP,EAAapR,MAAMO,SACpBkB,EAAYvG,EAAIwG,EAAmBvN,KAAKiM,UAAU/E,QAAQK,KAAO0V,EAAapR,MAAMyB,YAAYvG,EAAI/G,KAAKiM,UAAUlC,GAAK,GAExHuD,EAAYvG,EAAI/G,KAAKiM,UAAUjC,GAAKiT,EAAapR,MAAMyB,YAAYvG,EAAI,IAIxEmW,EAAYO,UACbxd,EAASoM,WAAWkR,EAAgB9Z,EAAOzD,KAAMA,KAAK4c,WAAY5c,KAAKiM,UAAUjM,KAAK6M,aAAaY,OAAQsP,GACzGE,EAAaS,WAAWC,KACxBV,EAAaS,WAAW1d,KAAK2M,MAAMiR,MAClCnR,GAGFyQ,EAAYW,WACb5d,EAASmN,YAAYmQ,EAAgBC,EAAa/Z,EAAO4Z,EAAard,KAAMkd,EAAY3U,OAAQ+E,EAAa0P,GAC3GC,EAAaS,WAAWI,MACxBb,EAAaS,WAAW1d,KAAK2M,MAAMiR,KACnCX,EAAaS,WAAWR,EAAY9Q,WACnCmB,EAAkBd,KAEvB2G,KAAKpT,OAlGT,GAAIyc,IACF1V,GACE6F,IAAK,IACLa,IAAK,QACLmQ,IAAK,aACLjB,UAAW,KACXD,QAAS,KACTG,WAAY,MAEd/V,GACE8F,IAAK,IACLa,IAAK,SACLmQ,IAAK,WACLjB,UAAW,KACXD,QAAS,KACTG,WAAY,MAsFhB5c,GAASsc,KAAOtc,EAAS2R,MAAMlR,QAC7ByR,YAAaoK,EACbO,oBAAqBA,EACrBM,aAAc,SAASxb,EAAO6B,EAAOc,GACnC,KAAM,IAAIuG,OAAM,uCAIpB7K,EAASsc,KAAK5P,MAAQ8P,GAEtBtc,OAAQC,SAAUH,GAuBnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEA,SAAS8d,GAAcC,EAAUzZ,EAAM0H,EAAW7D,GAEhD,GAAIQ,GAAUR,EAAQQ,SAAW3I,EAASuI,WAAWjE,EAAK0Z,WAAY7V,EAAS4V,EAASpR,IACxF5M,MAAKiI,OAAShI,EAASgK,UAAUgC,EAAU+R,EAAStB,SAAWzQ,EAAU+R,EAASrB,WAAY/T,EAASR,EAAQ8B,eAAiB,GAAI9B,EAAQ+B,aAC5InK,KAAKkI,OACHkB,IAAKpJ,KAAKiI,OAAOmB,IACjB9F,IAAKtD,KAAKiI,OAAO3E,KAGnBrD,EAAS8d,cAAT9d,SAA6BkS,YAAYnR,KAAKhB,KAC5Cge,EACA/R,EACAjM,KAAKiI,OAAO8C,OACZ3C,GAGJ,QAASgV,GAAaxb,GACpB,MAAO5B,MAAKgI,aAAe/H,EAASuJ,cAAc5H,EAAO5B,KAAK2M,MAAMC,KAAO5M,KAAKiI,OAAOmB,KAAOpJ,KAAKiI,OAAOC,MAG5GjI,EAAS8d,cAAgB9d,EAASsc,KAAK7b,QACrCyR,YAAa4L,EACbX,aAAcA,KAGhBjd,OAAQC,SAAUH,GAqBnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEA,SAASie,GAAeF,EAAUzZ,EAAM0H,EAAW7D,GACjD,GAAIQ,GAAUR,EAAQQ,SAAW3I,EAASuI,WAAWjE,EAAK0Z,WAAY7V,EAAS4V,EAASpR,IACxF5M,MAAK8J,QAAU1B,EAAQ0B,SAAW,EAClC9J,KAAKwc,MAAQpU,EAAQoU,OAASvc,EAASqC,MAAMtC,KAAK8J,SAASvG,IAAI,SAAS3B,EAAO6B,GAC7E,MAAOmF,GAAQG,KAAOH,EAAQC,KAAOD,EAAQG,KAAO/I,KAAK8J,QAAUrG,GACnE2P,KAAKpT,OACPA,KAAKwc,MAAM2B,KAAK,SAAS7B,EAAG8B,GAC1B,MAAO9B,GAAI8B,IAEbpe,KAAKkI,OACHkB,IAAKR,EAAQG,IACbzF,IAAKsF,EAAQC,MAGf5I,EAASie,eAATje,SAA8BkS,YAAYnR,KAAKhB,KAC7Cge,EACA/R,EACAjM,KAAKwc,MACLpU,GAEFpI,KAAKqe,WAAare,KAAKgI,WAAahI,KAAK8J,QAG3C,QAASsT,GAAaxb,GACpB,MAAO5B,MAAKgI,aAAe/H,EAASuJ,cAAc5H,EAAO5B,KAAK2M,MAAMC,KAAO5M,KAAKkI,MAAMkB,MAAQpJ,KAAKkI,MAAM5E,IAAMtD,KAAKkI,MAAMkB,KAG5HnJ,EAASie,eAAiBje,EAASsc,KAAK7b,QACtCyR,YAAa+L,EACbd,aAAcA,KAGhBjd,OAAQC,SAAUH,GAiBnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEA,SAASqe,GAASN,EAAUzZ,EAAM0H,EAAW7D,GAC3CnI,EAASqe,SAATre,SAAwBkS,YAAYnR,KAAKhB,KACvCge,EACA/R,EACA7D,EAAQoU,MACRpU,GAEFpI,KAAKqe,WAAare,KAAKgI,YAAcI,EAAQoU,MAAMja,QAAU6F,EAAQmW,QAAU,EAAI,IAGrF,QAASnB,GAAaxb,EAAO6B,GAC3B,MAAOzD,MAAKqe,WAAa5a,EAG3BxD,EAASqe,SAAWre,EAASsc,KAAK7b,QAChCyR,YAAamM,EACblB,aAAcA,KAGhBjd,OAAQC,SAAUH,GASnB,SAASE,EAAQC,EAAUH,GAC1B,YAuGA,SAAS0S,GAAYvK,GACnB,GAAI7D,IACFia,IAAKxe,KAAKuE,KACV0Z,WAAYhe,EAASsG,aAAavG,KAAKuE,KAAM6D,EAAQlC,aAAa,GAIpElG,MAAKqF,IAAMpF,EAAS+E,UAAUhF,KAAKiF,UAAWmD,EAAQlD,MAAOkD,EAAQjD,OAAQiD,EAAQsV,WAAWe,MAEhG,IAKInW,GAAOuD,EALPkR,EAAY/c,KAAKqF,IAAI0H,KAAK,KAAKjH,SAASsC,EAAQsV,WAAWX,WAC3D2B,EAAc1e,KAAKqF,IAAI0H,KAAK,KAC5BiQ,EAAahd,KAAKqF,IAAI0H,KAAK,KAAKjH,SAASsC,EAAQsV,WAAWV,YAE5D/Q,EAAYhM,EAASyL,gBAAgB1L,KAAKqF,IAAK+C,EAAS6G,EAAe/H,QAIzEoB,GADwBpG,SAAvBkG,EAAQE,MAAM4E,KACP,GAAIjN,GAASqe,SAASre,EAASsc,KAAK5P,MAAM5F,EAAGxC,EAAM0H,EAAWhM,EAASS,UAAW0H,EAAQE,OAChGkU,MAAOjY,EAAKia,IAAIrY,OAChBoY,QAASnW,EAAQuW,aAGXvW,EAAQE,MAAM4E,KAAKlM,KAAKf,EAAUA,EAASsc,KAAK5P,MAAM5F,EAAGxC,EAAM0H,EAAW7D,EAAQE,OAI1FuD,EADwB3J,SAAvBkG,EAAQyD,MAAMqB,KACP,GAAIjN,GAAS8d,cAAc9d,EAASsc,KAAK5P,MAAM7F,EAAGvC,EAAM0H,EAAWhM,EAASS,UAAW0H,EAAQyD,OACrGhD,KAAM5I,EAASoJ,MAAMjB,EAAQS,MAAQT,EAAQS,KAAOT,EAAQyD,MAAMhD,KAClEE,IAAK9I,EAASoJ,MAAMjB,EAAQW,KAAOX,EAAQW,IAAMX,EAAQyD,MAAM9C,OAGzDX,EAAQyD,MAAMqB,KAAKlM,KAAKf,EAAUA,EAASsc,KAAK5P,MAAM7F,EAAGvC,EAAM0H,EAAW7D,EAAQyD,OAG5FvD,EAAMwU,oBAAoBC,EAAWC,EAAYhd,KAAKwT,sBAAuBpL,EAASpI,KAAKyM,cAC3FZ,EAAMiR,oBAAoBC,EAAWC,EAAYhd,KAAKwT,sBAAuBpL,EAASpI,KAAKyM,cAG3FlI,EAAKia,IAAInY,OAAOnF,QAAQ,SAASmF,EAAQuY,GACvC,GAAIC,GAAgBH,EAAY3R,KAAK,IAGrC8R,GAAchZ,MACZiZ,cAAezY,EAAOyH,KACtBrG,KAAQxH,EAASqE,UAAU+B,EAAOoB,OACjCxH,EAASwF,MAAM4O,KAGlBwK,EAAc/Y,UACZsC,EAAQsV,WAAWrX,OAClBA,EAAOjB,WAAagD,EAAQsV,WAAWrX,OAAS,IAAMpG,EAASM,cAAcqe,IAC9E5R,KAAK,KAEP,IAAImC,MACF4P,IAEFxa,GAAK0Z,WAAWW,GAAa1d,QAAQ,SAASU,EAAOod,GACnD,GAAIrV,IACF5C,EAAGkF,EAAUlC,GAAKzB,EAAM8U,aAAaxb,EAAOod,EAAYza,EAAK0Z,WAAWW,IACxE9X,EAAGmF,EAAUC,GAAKL,EAAMuR,aAAaxb,EAAOod,EAAYza,EAAK0Z,WAAWW,IAE1EzP,GAAgBnE,KAAKrB,EAAE5C,EAAG4C,EAAE7C,GAC5BiY,EAAS/T,MACPpJ,MAAOA,EACPod,WAAYA,EACZvX,KAAMxH,EAASuH,YAAYnB,EAAQ2Y,MAErC5L,KAAKpT,MAEP,IAAI+N,IACFkR,WAAYhf,EAAS4N,gBAAgBxH,EAAQ+B,EAAS,cACtD8W,UAAWjf,EAAS4N,gBAAgBxH,EAAQ+B,EAAS,aACrD+W,SAAUlf,EAAS4N,gBAAgBxH,EAAQ+B,EAAS,YACpDgX,SAAUnf,EAAS4N,gBAAgBxH,EAAQ+B,EAAS,YACpDiX,SAAUpf,EAAS4N,gBAAgBxH,EAAQ+B,EAAS,aAGlDkX,EAAgD,kBAA7BvR,GAAckR,WACnClR,EAAckR,WAAclR,EAAckR,WAAahf,EAAS8O,cAAcoB,WAAalQ,EAAS8O,cAAcC,OAGhHK,EAAOiQ,EAAUnQ,EAAiB4P,EAqCtC,IAhCIhR,EAAcmR,WAEhB7P,EAAK2K,aAAa9Y,QAAQ,SAASgZ,GACjC,GAAIqF,GAAQV,EAAc9R,KAAK,QAC7BhD,GAAImQ,EAAYnT,EAChBmF,GAAIgO,EAAYpT,EAChBkD,GAAIkQ,EAAYnT,EAAI,IACpBoF,GAAI+N,EAAYpT,GACfsB,EAAQsV,WAAW6B,OAAO1Z,MAC3BjE,OAAUsY,EAAY3V,KAAK3C,MAAMmF,EAAGmT,EAAY3V,KAAK3C,MAAMkF,GAAGvB,OAAO,SAASia,GAC1E,MAAOA,KACNxS,KAAK,KACVvF,KAAQyS,EAAY3V,KAAKkD,MACxBxH,EAASwF,MAAM4O,IAElBrU,MAAKyM,aAAaQ,KAAK,QACrBC,KAAM,QACNtL,MAAOsY,EAAY3V,KAAK3C,MACxB6B,MAAOyW,EAAY3V,KAAKya,WACxBvX,KAAMyS,EAAY3V,KAAKkD,KACvBpB,OAAQA,EACRuY,YAAaA,EACbtW,MAAOA,EACPuD,MAAOA,EACPU,MAAOsS,EACP1R,QAASoS,EACTxY,EAAGmT,EAAYnT,EACfD,EAAGoT,EAAYpT,KAEjBsM,KAAKpT,OAGN+N,EAAcoR,SAAU,CACzB,GAAIvP,GAAOiP,EAAc9R,KAAK,QAC5B+C,EAAGT,EAAK5K,aACP2D,EAAQsV,WAAW9N,MAAM,EAE5B5P,MAAKyM,aAAaQ,KAAK,QACrBC,KAAM,OACNnC,OAAQxG,EAAK0Z,WAAWW,GACxBvP,KAAMA,EAAK2M,QACX/P,UAAWA,EACXxI,MAAOmb,EACPvY,OAAQA,EACRuY,YAAaA,EACbtW,MAAOA,EACPuD,MAAOA,EACPU,MAAOsS,EACP1R,QAASyC,IAKb,GAAG7B,EAAcqR,UAAYvT,EAAM3D,MAAO,CAGxC,GAAImX,GAAWhc,KAAKC,IAAID,KAAK+F,IAAI2E,EAAcsR,SAAUxT,EAAM3D,MAAM5E,KAAMuI,EAAM3D,MAAMkB,KAGnFqW,EAAoBxT,EAAUC,GAAKL,EAAMuR,aAAaiC,EAG1DhQ,GAAK4M,eAAe,KAAK1W,OAAO,SAA2Bma,GAEzD,MAAOA,GAAY1F,aAAazX,OAAS,IACxCgB,IAAI,SAAuBoc,GAE5B,GAAIC,GAAeD,EAAkB3F,aAAa,GAC9C6F,EAAcF,EAAkB3F,aAAa2F,EAAkB3F,aAAazX,OAAS,EAMzF,OAAOod,GAAkB3D,OAAM,GAC5B5P,SAAS,GACTqJ,OAAO,GACP9F,KAAKiQ,EAAa7Y,EAAG0Y,GACrB7P,KAAKgQ,EAAa7Y,EAAG6Y,EAAa9Y,GAClCsF,SAASuT,EAAkB3F,aAAazX,OAAS,GACjDqN,KAAKiQ,EAAY9Y,EAAG0Y,KAEtBve,QAAQ,SAAoB4e,GAG7B,GAAIC,GAAOlB,EAAc9R,KAAK,QAC5B+C,EAAGgQ,EAASrb,aACX2D,EAAQsV,WAAWqC,MAAM,GAAMla,MAChCkF,OAAUxG,EAAK0Z,WAAWW,IACzB3e,EAASwF,MAAM4O,IAGlBrU,MAAKyM,aAAaQ,KAAK,QACrBC,KAAM,OACNnC,OAAQxG,EAAK0Z,WAAWW,GACxBvP,KAAMyQ,EAAS9D,QACf3V,OAAQA,EACRuY,YAAaA,EACbtW,MAAOA,EACPuD,MAAOA,EACPI,UAAWA,EACXxI,MAAOmb,EACPrS,MAAOsS,EACP1R,QAAS4S,KAEX3M,KAAKpT,SAEToT,KAAKpT,OAEPA,KAAKyM,aAAaQ,KAAK,WACrBhF,OAAQ4D,EAAM5D,OACdgE,UAAWA,EACX3D,MAAOA,EACPuD,MAAOA,EACPxG,IAAKrF,KAAKqF,IACV+C,QAASA,IAqFb,QAAS4X,GAAK5d,EAAOmC,EAAM6D,EAAS6F,GAClChO,EAAS+f,KAAT/f,SAAoBkS,YAAYnR,KAAKhB,KACnCoC,EACAmC,EACA0K,EACAhP,EAASS,UAAWuO,EAAgB7G,GACpC6F,GApYJ,GAAIgB,IAEF3G,OAEEC,OAAQ,GAER6D,SAAU,MAEVkB,aACEvG,EAAG,EACHD,EAAG,GAGL+W,WAAW,EAEXJ,UAAU,EAEVH,sBAAuBrd,EAASI,KAEhC6M,KAAMhL,QAGR2J,OAEEtD,OAAQ,GAER6D,SAAU,QAEVkB,aACEvG,EAAG,EACHD,EAAG,GAGL+W,WAAW,EAEXJ,UAAU,EAEVH,sBAAuBrd,EAASI,KAEhC6M,KAAMhL,OAENgI,cAAe,GAEfC,aAAa,GAGfjF,MAAOhD,OAEPiD,OAAQjD,OAERid,UAAU,EAEVD,WAAW,EAEXE,UAAU,EAEVC,SAAU,EAEVJ,YAAY,EAEZlW,IAAK7G,OAEL2G,KAAM3G,OAENmG,cACEjB,IAAK,GACLC,MAAO,GACPC,OAAQ,EACRC,KAAM,IAGRoX,WAAW,EAEXzY,aAAa,EAEbwX,YACEe,MAAO,gBACPX,MAAO,WACPd,WAAY,YACZ3W,OAAQ,YACRuJ,KAAM,UACN2P,MAAO,WACPQ,KAAM,UACNpC,KAAM,UACNZ,UAAW,WACXkD,SAAU,cACVC,WAAY,gBACZC,MAAO,WACPC,IAAK,UAgTTngB,GAAS+f,KAAO/f,EAASsT,KAAK7S,QAC5ByR,YAAa6N,EACbrN,YAAaA,KAGfxS,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAuGA,SAAS0S,GAAYvK,GACnB,GAOIQ,GAPArE,GACFia,IAAKxe,KAAKuE,KACV0Z,WAAY7V,EAAQiY,iBAAmBpgB,EAASsG,aAAavG,KAAKuE,KAAM6D,EAAQlC,YAAakC,EAAQkY,eAAiB,IAAM,KAAK/c,IAAI,SAAS3B,GAC5I,OAAQA,KACL3B,EAASsG,aAAavG,KAAKuE,KAAM6D,EAAQlC,YAAakC,EAAQkY,eAAiB,IAAM,KAM5FtgB,MAAKqF,IAAMpF,EAAS+E,UAClBhF,KAAKiF,UACLmD,EAAQlD,MACRkD,EAAQjD,OACRiD,EAAQsV,WAAWe,OAASrW,EAAQkY,eAAiB,IAAMlY,EAAQsV,WAAW4C,eAAiB,IAIjG,IAAIvD,GAAY/c,KAAKqF,IAAI0H,KAAK,KAAKjH,SAASsC,EAAQsV,WAAWX,WAC3D2B,EAAc1e,KAAKqF,IAAI0H,KAAK,KAC5BiQ,EAAahd,KAAKqF,IAAI0H,KAAK,KAAKjH,SAASsC,EAAQsV,WAAWV,WAEhE,IAAG5U,EAAQmY,UAAW,CAEpB,GAAIC,GAAavgB,EAASgD,UAAUsB,EAAK0Z,WAAY,WACnD,MAAOpd,OAAMC,UAAUC,MAAMC,KAAKC,WAAWsC,IAAI,SAAS3B,GACxD,MAAOA,KACNgD,OAAO,SAAS6b,EAAMC,GACvB,OACE3Z,EAAG0Z,EAAK1Z,EAAI2Z,EAAK3Z,GAAK,EACtBD,EAAG2Z,EAAK3Z,EAAI4Z,EAAK5Z,GAAK,KAEtBC,EAAG,EAAGD,EAAG,KAGf8B,GAAU3I,EAASuI,YAAYgY,GAAavgB,EAASS,UAAW0H,GAC9De,eAAgB,IACdf,EAAQkY,eAAiB,IAAM,SAEnC1X,GAAU3I,EAASuI,WAAWjE,EAAK0Z,WAAYhe,EAASS,UAAW0H,GACjEe,eAAgB,IACdf,EAAQkY,eAAiB,IAAM,IAGrC1X,GAAQC,MAAQT,EAAQS,OAA0B,IAAjBT,EAAQS,KAAa,EAAID,EAAQC,MAClED,EAAQG,KAAOX,EAAQW,MAAwB,IAAhBX,EAAQW,IAAY,EAAIH,EAAQG,IAE/D,IAEI4X,GACFC,EACAC,EACAvY,EACAuD,EANEI,EAAYhM,EAASyL,gBAAgB1L,KAAKqF,IAAK+C,EAAS6G,EAAe/H,QAYzE0Z,GAHCxY,EAAQiY,kBAAoBjY,EAAQmY,UAGpBhc,EAAKia,IAAIrY,OAAOpF,MAAM,EAAG,GAKzBwD,EAAKia,IAAIrY,OAIzBiC,EAAQkY,gBAEPK,EAAYrY,EADYpG,SAAvBkG,EAAQE,MAAM4E,KACK,GAAIjN,GAAS8d,cAAc9d,EAASsc,KAAK5P,MAAM5F,EAAGxC,EAAM0H,EAAWhM,EAASS,UAAW0H,EAAQE,OACjHM,QAASA,EACTO,eAAgB,KAGEf,EAAQE,MAAM4E,KAAKlM,KAAKf,EAAUA,EAASsc,KAAK5P,MAAM5F,EAAGxC,EAAM0H,EAAWhM,EAASS,UAAW0H,EAAQE,OACxHM,QAASA,EACTO,eAAgB,KAKlB0X,EAAYhV,EADY3J,SAAvBkG,EAAQyD,MAAMqB,KACK,GAAIjN,GAASqe,SAASre,EAASsc,KAAK5P,MAAM7F,EAAGvC,EAAM0H,GACrEuQ,MAAOoE,IAGWxY,EAAQyD,MAAMqB,KAAKlM,KAAKf,EAAUA,EAASsc,KAAK5P,MAAM7F,EAAGvC,EAAM0H,EAAW7D,EAAQyD,SAItGgV,EAAYvY,EADYpG,SAAvBkG,EAAQE,MAAM4E,KACK,GAAIjN,GAASqe,SAASre,EAASsc,KAAK5P,MAAM5F,EAAGxC,EAAM0H,GACrEuQ,MAAOoE,IAGWxY,EAAQE,MAAM4E,KAAKlM,KAAKf,EAAUA,EAASsc,KAAK5P,MAAM5F,EAAGxC,EAAM0H,EAAW7D,EAAQE,OAItGqY,EAAY9U,EADY3J,SAAvBkG,EAAQyD,MAAMqB,KACK,GAAIjN,GAAS8d,cAAc9d,EAASsc,KAAK5P,MAAM7F,EAAGvC,EAAM0H,EAAWhM,EAASS,UAAW0H,EAAQyD,OACjHjD,QAASA,EACTO,eAAgB,KAGEf,EAAQyD,MAAMqB,KAAKlM,KAAKf,EAAUA,EAASsc,KAAK5P,MAAM7F,EAAGvC,EAAM0H,EAAWhM,EAASS,UAAW0H,EAAQyD,OACxHjD,QAASA,EACTO,eAAgB,KAMtB,IAAI2X,GAAY1Y,EAAQkY,eAAkBrU,EAAUlC,GAAK4W,EAAUvD,aAAa,GAAOnR,EAAUC,GAAKyU,EAAUvD,aAAa,GAEzH2D,IAEJF,GAAU/D,oBAAoBC,EAAWC,EAAYhd,KAAKwT,sBAAuBpL,EAASpI,KAAKyM,cAC/FkU,EAAU7D,oBAAoBC,EAAWC,EAAYhd,KAAKwT,sBAAuBpL,EAASpI,KAAKyM,cAG/FlI,EAAKia,IAAInY,OAAOnF,QAAQ,SAASmF,EAAQuY,GAEvC,GAEIoC,GAEAnC,EAJAoC,EAAQrC,GAAera,EAAKia,IAAInY,OAAO9D,OAAS,GAAK,CAUvDye,GAHC5Y,EAAQiY,mBAAqBjY,EAAQmY,UAGnBM,EAAU7Y,WAAazD,EAAK0Z,WAAW1b,OAAS,EAC3D6F,EAAQiY,kBAAoBjY,EAAQmY,UAGzBM,EAAU7Y,WAAa,EAGvB6Y,EAAU7Y,WAAazD,EAAK0Z,WAAWW,GAAarc,OAAS,EAIlFsc,EAAgBH,EAAY3R,KAAK,KAGjC8R,EAAchZ,MACZiZ,cAAezY,EAAOyH,KACtBrG,KAAQxH,EAASqE,UAAU+B,EAAOoB,OACjCxH,EAASwF,MAAM4O,KAGlBwK,EAAc/Y,UACZsC,EAAQsV,WAAWrX,OAClBA,EAAOjB,WAAagD,EAAQsV,WAAWrX,OAAS,IAAMpG,EAASM,cAAcqe,IAC9E5R,KAAK,MAEPzI,EAAK0Z,WAAWW,GAAa1d,QAAQ,SAASU,EAAOod,GACnD,GAAIkC,GACFC,EACAC,EACAC,CA+CF,IAzCEA,EAHCjZ,EAAQiY,mBAAqBjY,EAAQmY,UAGhB3B,EACdxW,EAAQiY,kBAAoBjY,EAAQmY,UAGtB,EAGAvB,EAKtBkC,EADC9Y,EAAQkY,gBAEPvZ,EAAGkF,EAAUlC,GAAK4W,EAAUvD,aAAaxb,GAASA,EAAMmF,EAAInF,EAAMmF,EAAI,EAAGiY,EAAYza,EAAK0Z,WAAWW,IACrG9X,EAAGmF,EAAUC,GAAK2U,EAAUzD,aAAaxb,GAASA,EAAMkF,EAAIlF,EAAMkF,EAAI,EAAGua,EAAqB9c,EAAK0Z,WAAWW,MAI9G7X,EAAGkF,EAAUlC,GAAK8W,EAAUzD,aAAaxb,GAASA,EAAMmF,EAAInF,EAAMmF,EAAI,EAAGsa,EAAqB9c,EAAK0Z,WAAWW,IAC9G9X,EAAGmF,EAAUC,GAAKyU,EAAUvD,aAAaxb,GAASA,EAAMkF,EAAIlF,EAAMkF,EAAI,EAAGkY,EAAYza,EAAK0Z,WAAWW,KAQtGiC,YAAqB5gB,GAASqe,WAE3BuC,EAAUzY,QAAQmW,UACpB2C,EAAUL,EAAUlU,MAAMC,MAAQoU,GAAoB5Y,EAAQkY,eAAiB,GAAK,IAGtFY,EAAUL,EAAUlU,MAAMC,MAASxE,EAAQmY,WAAanY,EAAQiY,iBAAoB,EAAIY,EAAQ7Y,EAAQkZ,mBAAqBlZ,EAAQkY,eAAiB,GAAK,IAI7Jc,EAAgBL,EAAiB/B,IAAe8B,EAChDC,EAAiB/B,GAAcoC,GAAiBN,EAAYI,EAAUL,EAAUhU,aAAaD,MAGhF1K,SAAVN,EAAH,CAIA,GAAI2f,KACJA,GAAUV,EAAUlU,MAAMC,IAAM,KAAOsU,EAAUL,EAAUlU,MAAMC,KACjE2U,EAAUV,EAAUlU,MAAMC,IAAM,KAAOsU,EAAUL,EAAUlU,MAAMC,MAE9DxE,EAAQmY,WAAoC,eAAtBnY,EAAQoZ,WAA+BpZ,EAAQoZ,WAUtED,EAAUV,EAAUhU,aAAaD,IAAM,KAAOkU,EAC9CS,EAAUV,EAAUhU,aAAaD,IAAM,KAAOsU,EAAUL,EAAUhU,aAAaD,OAN/E2U,EAAUV,EAAUhU,aAAaD,IAAM,KAAOwU,EAC9CG,EAAUV,EAAUhU,aAAaD,IAAM,KAAOmU,EAAiB/B,IASjEuC,EAAUxX,GAAK1G,KAAK+F,IAAI/F,KAAKC,IAAIie,EAAUxX,GAAIkC,EAAUlC,IAAKkC,EAAUjC;AACxEuX,EAAUvX,GAAK3G,KAAK+F,IAAI/F,KAAKC,IAAIie,EAAUvX,GAAIiC,EAAUlC,IAAKkC,EAAUjC,IACxEuX,EAAUrV,GAAK7I,KAAK+F,IAAI/F,KAAKC,IAAIie,EAAUrV,GAAID,EAAUE,IAAKF,EAAUC,IACxEqV,EAAUpV,GAAK9I,KAAK+F,IAAI/F,KAAKC,IAAIie,EAAUpV,GAAIF,EAAUE,IAAKF,EAAUC,IAGxEiV,EAAMtC,EAAc9R,KAAK,OAAQwU,EAAWnZ,EAAQsV,WAAWyD,KAAKtb,MAClEjE,OAAUA,EAAMmF,EAAGnF,EAAMkF,GAAGvB,OAAO,SAASia,GAC1C,MAAOA,KACNxS,KAAK,KACRvF,KAAQxH,EAASuH,YAAYnB,EAAQ2Y,IACpC/e,EAASwF,MAAM4O,KAElBrU,KAAKyM,aAAaQ,KAAK,OAAQhN,EAASS,QACtCwM,KAAM,MACNtL,MAAOA,EACP6B,MAAOub,EACPvX,KAAMxH,EAASuH,YAAYnB,EAAQ2Y,GACnC3Y,OAAQA,EACRuY,YAAaA,EACbtW,MAAOA,EACPuD,MAAOA,EACPI,UAAWA,EACXM,MAAOsS,EACP1R,QAASgU,GACRI,MACHnO,KAAKpT,QACPoT,KAAKpT,OAEPA,KAAKyM,aAAaQ,KAAK,WACrBhF,OAAQ0Y,EAAU1Y,OAClBgE,UAAWA,EACX3D,MAAOA,EACPuD,MAAOA,EACPxG,IAAKrF,KAAKqF,IACV+C,QAASA,IAyCb,QAASqZ,GAAIrf,EAAOmC,EAAM6D,EAAS6F,GACjChO,EAASwhB,IAATxhB,SAAmBkS,YAAYnR,KAAKhB,KAClCoC,EACAmC,EACA0K,EACAhP,EAASS,UAAWuO,EAAgB7G,GACpC6F,GAzZJ,GAAIgB,IAEF3G,OAEEC,OAAQ,GAER6D,SAAU,MAEVkB,aACEvG,EAAG,EACHD,EAAG,GAGL+W,WAAW,EAEXJ,UAAU,EAEVH,sBAAuBrd,EAASI,KAEhC6J,cAAe,GAEfC,aAAa,GAGf0B,OAEEtD,OAAQ,GAER6D,SAAU,QAEVkB,aACEvG,EAAG,EACHD,EAAG,GAGL+W,WAAW,EAEXJ,UAAU,EAEVH,sBAAuBrd,EAASI,KAEhC6J,cAAe,GAEfC,aAAa,GAGfjF,MAAOhD,OAEPiD,OAAQjD,OAER2G,KAAM3G,OAEN6G,IAAK7G,OAELiI,aAAa,EAEb9B,cACEjB,IAAK,GACLC,MAAO,GACPC,OAAQ,EACRC,KAAM,IAGR+Z,kBAAmB,GAEnBf,WAAW,EAGXiB,UAAW,aAEXlB,gBAAgB,EAEhBD,kBAAkB,EAElBna,aAAa,EAEbwX,YACEe,MAAO,eACP6B,eAAgB,qBAChBxC,MAAO,WACPd,WAAY,YACZ3W,OAAQ,YACR8a,IAAK,SACLxD,KAAM,UACNZ,UAAW,WACXkD,SAAU,cACVC,WAAY,gBACZC,MAAO,WACPC,IAAK,UAqUTngB,GAASwhB,IAAMxhB,EAASsT,KAAK7S,QAC3ByR,YAAasP,EACb9O,YAAaA,KAGfxS,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAsDA,SAASyhB,GAAwBC,EAAQ7D,EAAO8D,GAC9C,GAAIC,GAAa/D,EAAM/W,EAAI4a,EAAO5a,CAElC,OAAG8a,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SASX,QAASjP,GAAYvK,GACnB,GACE0Z,GACA7V,EACAb,EACA2W,EACAC,EALEC,KAMFC,EAAa9Z,EAAQ8Z,WACrBC,EAAYliB,EAASsG,aAAavG,KAAKuE,KAAM6D,EAAQlC,YAGvDlG,MAAKqF,IAAMpF,EAAS+E,UAAUhF,KAAKiF,UAAWmD,EAAQlD,MAAOkD,EAAQjD,OAAOiD,EAAQga,MAAQha,EAAQsV,WAAW2E,WAAaja,EAAQsV,WAAW4E,UAE/IrW,EAAYhM,EAASyL,gBAAgB1L,KAAKqF,IAAK+C,EAAS6G,EAAe/H,SAEvEkE,EAAS/H,KAAK+F,IAAI6C,EAAU/G,QAAU,EAAG+G,EAAU9G,SAAW,GAE9D6c,EAAe5Z,EAAQma,OAASJ,EAAUvd,OAAO,SAAS4d,EAAeC,GACvE,MAAOD,GAAgBC,GACtB,EAEH,IAAIC,GAAaziB,EAAS6B,SAASsG,EAAQsa,WACnB,OAApBA,EAAW7gB,OACb6gB,EAAW9gB,OAASwJ,EAAS,KAM/BA,GAAUhD,EAAQga,MAAQM,EAAW9gB,MAAQ,EAAK,EAKhDmgB,EAD2B,YAA1B3Z,EAAQua,eAA+Bva,EAAQga,MAClChX,EACoB,WAA1BhD,EAAQua,cAEF,EAIAvX,EAAS,EAGzB2W,GAAe3Z,EAAQkF,WAGvB,IAAIqU,IACF5a,EAAGkF,EAAUlC,GAAKkC,EAAU/G,QAAU,EACtC4B,EAAGmF,EAAUE,GAAKF,EAAU9G,SAAW,GAIrCyd,EAEU,IAFa5iB,KAAKuE,KAAK8B,OAAOd,OAAO,SAASsd,GAC1D,MAAOA,GAAIlc,eAAe,SAAyB,IAAdkc,EAAIjhB,MAAsB,IAARihB,IACtDtgB,MAGA6F,GAAQyV,YACTiE,EAAc9hB,KAAKqF,IAAI0H,KAAK,IAAK,KAAM,MAAM,GAK/C,KAAK,GAAIzG,GAAI,EAAGA,EAAItG,KAAKuE,KAAK8B,OAAO9D,OAAQ+D,IAAK,CAChD,GAAID,GAASrG,KAAKuE,KAAK8B,OAAOC,EAC9B2b,GAAa3b,GAAKtG,KAAKqF,IAAI0H,KAAK,IAAK,KAAM,MAAM,GAGjDkV,EAAa3b,GAAGT,MACdiZ,cAAezY,EAAOyH,MACrB7N,EAASwF,MAAM4O,KAGlB4N,EAAa3b,GAAGR,UACdsC,EAAQsV,WAAWrX,OAClBA,EAAOjB,WAAagD,EAAQsV,WAAWrX,OAAS,IAAMpG,EAASM,cAAc+F,IAC9E0G,KAAK,KAEP,IAAI8V,GAAWZ,EAAaC,EAAU7b,GAAK0b,EAAe,GAGvDc,GAAWZ,IAAe,MAC3BY,GAAY,IAGd,IAAI3C,GAAQlgB,EAASgL,iBAAiB0W,EAAO5a,EAAG4a,EAAO7a,EAAGsE,EAAQ8W,GAAoB,IAAN5b,GAAWsc,EAAuB,EAAI,KACpHxC,EAAMngB,EAASgL,iBAAiB0W,EAAO5a,EAAG4a,EAAO7a,EAAGsE,EAAQ0X,GAG1DzT,EAAO,GAAIpP,GAAS2F,IAAI0J,MAAMlH,EAAQga,OACvCzS,KAAKyQ,EAAIrZ,EAAGqZ,EAAItZ,GAChB8T,IAAIxP,EAAQA,EAAQ,EAAG0X,EAAWZ,EAAa,IAAK,EAAG/B,EAAMpZ,EAAGoZ,EAAMrZ,EAGrEsB,GAAQga,OACV/S,EAAKO,KAAK+R,EAAO5a,EAAG4a,EAAO7a,EAK7B,IAAIoT,GAAc+H,EAAa3b,GAAGyG,KAAK,QACrC+C,EAAGT,EAAK5K,aACP2D,EAAQga,MAAQha,EAAQsV,WAAWqF,WAAa3a,EAAQsV,WAAWsF,SAiCtE,IA9BA9I,EAAYrU,MACVjE,MAASugB,EAAU7b,GACnBmB,KAAQxH,EAASqE,UAAU+B,EAAOoB,OACjCxH,EAASwF,MAAM4O,KAGfjM,EAAQga,OACTlI,EAAYrU,MACVE,MAAS,iBAAmB2c,EAAW9gB,MAAQ,OAKnD5B,KAAKyM,aAAaQ,KAAK,QACrBC,KAAM,QACNtL,MAAOugB,EAAU7b,GACjB0b,aAAcA,EACdve,MAAO6C,EACPmB,KAAMpB,EAAOoB,KACbpB,OAAQA,EACRkG,MAAO0V,EAAa3b,GACpB6G,QAAS+M,EACT7K,KAAMA,EAAK2M,QACX2F,OAAQA,EACRvW,OAAQA,EACR8W,WAAYA,EACZY,SAAUA,IAIT1a,EAAQyV,UAAW,CAEpB,GAAI8E,GAAgB1iB,EAASgL,iBAAiB0W,EAAO5a,EAAG4a,EAAO7a,EAAGib,EAAaG,GAAcY,EAAWZ,GAAc,GACpHe,EAAoB7a,EAAQkV,sBAAsBtd,KAAKuE,KAAK4B,OAASnG,KAAKuE,KAAK4B,OAAOG,GAAK6b,EAAU7b,GAAIA,EAE3G,IAAG2c,GAA2C,IAAtBA,EAAyB,CAC/C,GAAIzV,GAAesU,EAAY/U,KAAK,QAClCmW,GAAIP,EAAc5b,EAClBoc,GAAIR,EAAc7b,EAClBsc,cAAe1B,EAAwBC,EAAQgB,EAAeva,EAAQib,iBACrEjb,EAAQsV,WAAWI,OAAOlQ,KAAK,GAAKqV,EAGvCjjB,MAAKyM,aAAaQ,KAAK,QACrBC,KAAM,QACNzJ,MAAO6C,EACPiG,MAAOuV,EACP3U,QAASK,EACTI,KAAM,GAAKqV,EACXlc,EAAG4b,EAAc5b,EACjBD,EAAG6b,EAAc7b,KAOvBob,EAAaY,EAGf9iB,KAAKyM,aAAaQ,KAAK,WACrBhB,UAAWA,EACX5G,IAAKrF,KAAKqF,IACV+C,QAASA,IAwEb,QAASkb,GAAIlhB,EAAOmC,EAAM6D,EAAS6F,GACjChO,EAASqjB,IAATrjB,SAAmBkS,YAAYnR,KAAKhB,KAClCoC,EACAmC,EACA0K,EACAhP,EAASS,UAAWuO,EAAgB7G,GACpC6F,GAzTJ,GAAIgB,IAEF/J,MAAOhD,OAEPiD,OAAQjD,OAERmG,aAAc,EAEdqV,YACE4E,SAAU,eACVD,WAAY,iBACZhc,OAAQ,YACR2c,SAAU,eACVD,WAAY,iBACZjF,MAAO,YAGToE,WAAY,EAEZK,MAAOrgB,OAEPkgB,OAAO,EAGPM,WAAY,GAEZ7E,WAAW,EAEXvQ,YAAa,EAEbqV,cAAe,SAEfrF,sBAAuBrd,EAASI,KAEhCgjB,eAAgB,UAEhBnd,aAAa,EAyRfjG,GAASqjB,IAAMrjB,EAASsT,KAAK7S,QAC3ByR,YAAamR,EACb3Q,YAAaA,EACb+O,wBAAyBA,KAG3BvhB,OAAQC,SAAUH,GAEbA","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([], 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.9.5\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.5'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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 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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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","exports","module","this","Chartist","version","window","document","namespaces","svg","xmlns","xhtml","xlink","ct","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","series","labels","labelCount","normalized","getDataArray","every","reverseData","reverse","i","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","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([], 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.9.6\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.9.6'\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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) {\n // Ensure data is present otherwise enforce\n data = data || {series: [], labels: []};\n data.series = data.series || [];\n data.labels = data.labels || [];\n\n // Check if we should generate some labels based on existing series data\n if (data.series.length > 0 && data.labels.length === 0) {\n var normalized = Chartist.getDataArray(data),\n labelCount;\n\n // If all elements of the normalized data array are arrays we're dealing with\n // data from Bar or Line charts and we need to find the largest series if they are un-even\n if (normalized.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, normalized.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 = normalized.length;\n }\n\n // Setting labels to an array with emptry strings using our labelCount estimated above\n data.labels = Chartist.times(labelCount).map(function() {\n return '';\n });\n }\n return data;\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\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 * 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 // 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.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 * 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 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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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.isNum).join(','),\n 'ct:meta': 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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[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 adition 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 // 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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),\n 'ct:meta': Chartist.getMetaData(series, valueIndex)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 this.data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;\n\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (i === 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[i].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': dataArray[i],\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);\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: i,\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 }\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/package.json b/package.json index a7705692..ed57043e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.5", + "version": "0.9.6", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { @@ -30,7 +30,11 @@ "licenses": [ { "type": "WTFPL", - "url": "https://github.com/gionkunz/chartist-js/blob/master/LICENSE" + "url": "https://github.com/gionkunz/chartist-js/blob/master/LICENSE-WTFPL" + }, + { + "type": "MIT", + "url": "https://github.com/gionkunz/chartist-js/blob/master/LICENSE-MIT" } ], "dependencies": {}, @@ -72,7 +76,7 @@ "test": "grunt test" }, "config": { - "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\n */\n", + "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> 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", "src": "src", "dist": "dist", "site": "site", From 4b16a81ae7b3c7f98620232ddb53e558ab259238 Mon Sep 17 00:00:00 2001 From: medzes Date: Mon, 9 Nov 2015 22:04:35 +0100 Subject: [PATCH 361/593] Small fix for stacked bars with 'holes' in the data --- src/scripts/charts/bar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index d871497a..77e73853 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -138,8 +138,8 @@ return value; }).reduce(function(prev, curr) { return { - x: prev.x + curr.x || 0, - y: prev.y + curr.y || 0 + x: prev.x + (curr && curr.x) || 0, + y: prev.y + (curr && curr.y) || 0 }; }, {x: 0, y: 0}); }); From c22bd2ec709f369066fdc64b2fdc9287453955f8 Mon Sep 17 00:00:00 2001 From: Alexandre Gigliotti Date: Wed, 18 Nov 2015 12:20:10 -0800 Subject: [PATCH 362/593] Add node-chartist to list of wrapper libraries. --- site/data/pages/index.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 150b0204..04c62798 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -216,6 +216,9 @@ sections: - Project - Type rows: + - + - 'node-chartist' + - Node Package for Server-side Charts - - 'ng-chartist.js' - Angular Directive From d6769a0d896af8b70b550e11cb21101eaeea8a9a Mon Sep 17 00:00:00 2001 From: madflow Date: Tue, 8 Dec 2015 20:12:49 +0100 Subject: [PATCH 363/593] Fix copy pasta --- site/data/pages/plugins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index ca8988d5..1bdcfce4 100755 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -253,7 +253,7 @@ sections: - Moxx - - 'Link:' - - 'chartist-plugin-threshold' + - 'chartist-plugin-fill-donut' - type: sub-section data: title: Zoom Plugin From 6fe2dd2ed0b5f85dee893d55364c84917b605849 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Sat, 12 Dec 2015 13:36:29 -0800 Subject: [PATCH 364/593] Fixed misspelling in overlapping bars example The original overlapping bars example spelled the month of May as "Mai". --- site/examples/overlapping-bars.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/examples/overlapping-bars.js b/site/examples/overlapping-bars.js index a8f16db1..8df7b813 100644 --- a/site/examples/overlapping-bars.js +++ b/site/examples/overlapping-bars.js @@ -1,5 +1,5 @@ var data = { - labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], series: [ [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8], [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4] @@ -21,4 +21,4 @@ var responsiveOptions = [ }] ]; -new Chartist.Bar('.ct-chart', data, options, responsiveOptions); \ No newline at end of file +new Chartist.Bar('.ct-chart', data, options, responsiveOptions); From abc65e3e15c61fc5d1be57402a9a26c0bfbd86b8 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Wed, 16 Dec 2015 10:41:07 +0100 Subject: [PATCH 365/593] Add fdescribe and fit to jshintrc. --- test/.jshintrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/.jshintrc b/test/.jshintrc index b0aa0ed4..f0bcac8a 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -26,9 +26,11 @@ "beforeEach": false, "browser": false, "describe": false, + "fdescribe": false, "expect": false, "inject": false, "it": false, + "fit": false, "jasmine": false, "spyOn": false, "$": false, From 7e43965aea019f098839974ad48ac30f36e821d2 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Wed, 16 Dec 2015 10:42:53 +0100 Subject: [PATCH 366/593] Fix #527 Pie render issue with small angles. --- src/scripts/charts/pie.js | 2 +- test/spec/spec-pie-chart.js | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 56728183..ca7caf41 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -164,7 +164,7 @@ endAngle -= 0.01; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); // 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 diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 4968e567..7df928b6 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -98,11 +98,39 @@ describe('Pie chart tests', function() { expect(labels.eq(2).text()).toBe('33%'); done(); }); - }); + }); + describe('Pie with small ratio', function() { + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var data = { + series: [0.001, 2] + }; + var options = { + width: 100, + height: 100, + chartPadding: 0, + }; + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('should render correctly with very small slices', function(done) { + onCreated(function() { + + var slice1 = $('.ct-slice-pie').eq(0); + var slice2 = $('.ct-slice-pie').eq(1); + expect(slice1.attr('d')).toMatch(/^M50,0A50,50,0,1,0,50.1\d+,0/); + expect(slice2.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/); + done(); + }); + }); + + }); describe('Gauge Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#gauge-chart From 4f4f9c3cbab976449c905b119a71795426d55bf2 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Thu, 17 Dec 2015 10:49:03 +0100 Subject: [PATCH 367/593] Fix pie render issues with overlaps and full circle arcs. --- src/scripts/charts/pie.js | 12 ++-- test/spec/spec-pie-chart.js | 126 ++++++++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 24 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index ca7caf41..01cdde8c 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -158,13 +158,17 @@ ].join(' ')); var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + + // Use slight offset so there are no transparent hairline issues + var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; + if(endAngle - overlappigStartAngle >= 359.99) { + endAngle = overlappigStartAngle + 359.99; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle), + var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); // 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 @@ -239,7 +243,7 @@ } } - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; } diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 7df928b6..7da5041a 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -37,12 +37,14 @@ describe('Pie chart tests', function() { describe('Simple Pie Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#simple-pie-chart - function onCreated(callback) { - jasmine.getFixtures().set('
    '); - var data = { + var num = '\\d+(\\.\\d*)?'; + var data, options; + + beforeEach(function() { + data = { series: [5, 3, 4] }; - var options = { + options = { width: 100, height: 100, chartPadding: 10, @@ -50,9 +52,11 @@ describe('Pie chart tests', function() { return Math.round(value / data.series.reduce(sum) * 100) + '%'; } }; - var sum = function(a, b) { return a + b; }; - + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); var chart = new Chartist.Pie('.ct-chart', data, options); chart.on('created', callback); } @@ -77,8 +81,6 @@ describe('Pie chart tests', function() { it('should create slice path', function(done) { onCreated(function() { $('.ct-slice-pie').each(function() { - - var num = '\\d+(\\.\\d*)?'; var pattern = '^M' + num + ',' + num + 'A40,40,0,0,0,' + num + ',' + num + @@ -99,36 +101,120 @@ describe('Pie chart tests', function() { done(); }); }); + + it('should overlap slices', function(done) { + data = { + series: [1, 1] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + var slice2 = $('.ct-slice-pie').eq(1); - }); + expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,0,0,50.\d+,90L50,50Z/); + expect(slice2.attr('d')).toMatch(/^M50,90A40,40,0,0,0,50,10L50,50Z/); + done(); + }); + }); + + it('should set large arc sweep flag', function(done) { + data = { + series: [1, 2] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,1,0/); + done(); + }, data); + }); - describe('Pie with small ratio', function() { + it('should draw complete circle with gap', function(done) { + data = { + series: [1] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + expect(slice1.attr('d')).toMatch(/^M49.9\d+,10A40,40,0,1,0,50,10L50,50Z/); + done(); + }); + }); - function onCreated(callback) { - jasmine.getFixtures().set('
    '); - var data = { + it('should draw complete circle with startAngle', function(done) { + data.series = [100]; + options.startAngle = 90; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + expect(slice1.attr('d')).toMatch(/^M90,49.9\d+A40,40,0,1,0,90,50L50,50Z/); + done(); + }); + }); + + it('should draw complete circle if values are 0', function(done) { + data = { + series: [0, 1, 0] + }; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(1); + expect(slice1.attr('d')).toMatch(/^M49.9\d+,10A40,40,0,1,0,50,10L50,50Z/); + done(); + }); + }); + + }); + + describe('Pie with small slices', function() { + var data, options; + + beforeEach(function() { + data = { series: [0.001, 2] }; - var options = { + options = { width: 100, height: 100, chartPadding: 0, - }; + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); var chart = new Chartist.Pie('.ct-chart', data, options); chart.on('created', callback); } - - it('should render correctly with very small slices', function(done) { - onCreated(function() { + it('Pie should render correctly with very small slices', function(done) { + onCreated(function() { var slice1 = $('.ct-slice-pie').eq(0); - var slice2 = $('.ct-slice-pie').eq(1); + var slice2 = $('.ct-slice-pie').eq(1); - expect(slice1.attr('d')).toMatch(/^M50,0A50,50,0,1,0,50.1\d+,0/); + expect(slice1.attr('d')).toMatch(/^M49.9\d*,0A50,50,0,1,0,50,0/); expect(slice2.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/); done(); }); }); + + it('Pie should render correctly with very small slices on startAngle', function(done) { + options.startAngle = 90; + onCreated(function() { + var slice1 = $('.ct-slice-pie').eq(0); + var slice2 = $('.ct-slice-pie').eq(1); + + expect(slice1.attr('d')).toMatch(/^M100,49.97\d*A50,50,0,1,0,100,49.98\d*/); + expect(slice2.attr('d')).toMatch(/^M100,50.1\d*A50,50,0,0,0,100,50/); + done(); + }); + }); + + it('Donut should render correctly with very small slices', function(done) { + options.donut = true; + onCreated(function() { + var slice1 = $('.ct-slice-donut').eq(0); + var slice2 = $('.ct-slice-donut').eq(1); + + expect(slice1.attr('d')).toMatch(/^M49.9\d*,30A20,20,0,1,0,50,30/); + expect(slice2.attr('d')).toMatch(/^M50.\d+,30A20,20,0,0,0,50,30/); + done(); + }); + }); }); From 57b9edb24674987dc0611abcbb236aa58e53cca0 Mon Sep 17 00:00:00 2001 From: Carlos Morales Date: Tue, 22 Dec 2015 13:55:04 +0100 Subject: [PATCH 368/593] fixes #537: Error on empty data set --- src/scripts/core.js | 5 ++++- src/scripts/interpolation.js | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index e7a70962..96d2b6eb 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -511,9 +511,12 @@ var Chartist = { } else if (highLow.low < 0) { // If we have the same negative value for the bounds we set bounds.high to 0 highLow.high = 0; - } else { + } else if (highLow.high > 0) { // If we have the same positive value for the bounds we set bounds.low to 0 highLow.low = 0; + } else { + // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors + highLow.high = highLow.low = 0; } } diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 8058d941..2c38f7b5 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -200,10 +200,13 @@ // This is necessary to treat "holes" in line charts var segments = splitIntoSegments(pathCoordinates, valueData); - // If the split resulted in more that one segment we need to interpolate each segment individually and join them - // afterwards together into a single path. - if(segments.length > 1) { - var paths = []; + if(!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return Chartist.Interpolation.none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; // For each segment we will recurse the cardinal function segments.forEach(function(segment) { paths.push(cardinal(segment.pathCoordinates, segment.valueData)); From d70eba3d2a30e1afd6097309b81c1f5b3118a789 Mon Sep 17 00:00:00 2001 From: Xiao Hanyu Date: Fri, 25 Dec 2015 20:51:20 +0800 Subject: [PATCH 369/593] Update getting-started.yml --- site/data/pages/getting-started.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 48071abe..25591c95 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -571,7 +571,7 @@ sections: - type: text data: text: > - In the following chapter you'll find some advanced usage examples that might be of interesst for you. + In the following chapter you'll find some advanced usage examples that might be of interest for you. Chartist is very flexible because it relies on standard technology. This also means that you will need to implement certain things yourself. This topic should cover some of these use-cases and give you some basic idea why and how to implement certain functionality. From 8d12a2f12495e846f4a8681c75b6d22fdf488e53 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Wed, 6 Jan 2016 15:48:16 +0000 Subject: [PATCH 370/593] Add Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9dcf99c5..348946be 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # Big welcome by the Chartist Guy + +[![Join the chat at https://gitter.im/gionkunz/chartist-js](https://badges.gitter.im/gionkunz/chartist-js.svg)](https://gitter.im/gionkunz/chartist-js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![npm version](http://img.shields.io/npm/v/chartist.svg)](https://npmjs.org/package/chartist) [![build status](http://img.shields.io/travis/gionkunz/chartist-js.svg)](https://travis-ci.org/gionkunz/chartist-js) [![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) ![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") From ff6bdf1615a64bfaf10e7c5c8e12fea7884734f4 Mon Sep 17 00:00:00 2001 From: Stephen Date: Sun, 10 Jan 2016 16:01:29 +0000 Subject: [PATCH 371/593] Allow empty pie chart values to be ignored Empty pie chart values can render with overlapping labels. This adds a configuration option to allow them to be ignored when rendering the pie chart. --- src/scripts/charts/pie.js | 7 +++- test/spec/spec-pie-chart.js | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 01cdde8c..8a57bb78 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -48,7 +48,9 @@ // 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. labelDirection: 'neutral', // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. - reverseData: false + reverseData: false, + // If true empty values will be ignored to avoid drawing unncessary slices and labels + ignoreEmptyValues: false }; /** @@ -143,6 +145,9 @@ // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { + // If current value is zero and we are ignoring empty values then skip to next value + if (dataArray[i] === 0 && options.ignoreEmptyValues) continue; + var series = this.data.series[i]; seriesGroups[i] = this.svg.elem('g', null, null, true); diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 7da5041a..f83d900c 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -217,6 +217,75 @@ describe('Pie chart tests', function() { }); }); + + describe('Pie with some empty values configured to be ignored', function() { + var data, options; + + beforeEach(function() { + data = { + series: [1, 2, 0, 4] + }; + options = { + width: 100, + height: 100, + ignoreEmptyValues: true + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('Pie should not render empty slices', function(done) { + onCreated(function() { + var slices = $('.ct-slice-pie'); + + expect(slices.length).toBe(3); + + expect(slices.eq(2).attr('ct:value')).toBe('1'); + expect(slices.eq(1).attr('ct:value')).toBe('2'); + expect(slices.eq(0).attr('ct:value')).toBe('4'); + done(); + }); + }); + }); + + describe('Pie with some empty values configured not to be ignored', function() { + var data, options; + + beforeEach(function() { + data = { + series: [1, 2, 0, 4] + }; + options = { + width: 100, + height: 100, + ignoreEmptyValues: false + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var chart = new Chartist.Pie('.ct-chart', data, options); + chart.on('created', callback); + } + + it('Pie should render empty slices', function(done) { + onCreated(function() { + var slices = $('.ct-slice-pie'); + + expect(slices.length).toBe(4); + + expect(slices.eq(3).attr('ct:value')).toBe('1'); + expect(slices.eq(2).attr('ct:value')).toBe('2'); + expect(slices.eq(1).attr('ct:value')).toBe('0'); + expect(slices.eq(0).attr('ct:value')).toBe('4'); + done(); + }); + }); + }); describe('Gauge Chart', function() { // https://gionkunz.github.io/chartist-js/examples.html#gauge-chart From 83d55b38e617b788736cc176ec8e6edbca449855 Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 02:16:16 -0500 Subject: [PATCH 372/593] render 0 in ct:value attribute for line graphs --- src/scripts/charts/line.js | 2 +- test/spec/spec-line-chart.js | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 00616e04..afe8437b 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -206,7 +206,7 @@ y2: pathElement.y }, options.classNames.point).attr({ 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { - return v; + return v || v === 0; }).join(','), 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index c16ddf72..f6c4bc17 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -9,6 +9,52 @@ describe('Line chart tests', function () { }); + describe('ct:value attribute', function () { + it('should contain x and y value for each datapoint', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + series: [[ + {x: 1, y: 2}, + {x: 3, y: 4} + ]] + }, { + axisX: { + type: Chartist.FixedScaleAxis + } + }); + + chart.on('created', function () { + expect($('.ct-point').eq(0).attr('ct:value')).toEqual('1,2'); + expect($('.ct-point').eq(1).attr('ct:value')).toEqual('3,4'); + done(); + }); + }); + + it('should render values that are zero', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + series: [[ + {x: 0, y: 1}, + {x: 1, y: 0}, + {x: 0, y: 0} + ]] + }, { + axisX: { + type: Chartist.FixedScaleAxis + } + }); + + chart.on('created', function () { + expect($('.ct-point').eq(0).attr('ct:value')).toEqual('0,1'); + expect($('.ct-point').eq(1).attr('ct:value')).toEqual('1,0'); + expect($('.ct-point').eq(2).attr('ct:value')).toEqual('0,0'); + done(); + }); + }); + }); + describe('Meta data tests', function () { it('should render meta data correctly with mixed value array', function (done) { jasmine.getFixtures().set('
    '); From f4c994e5aedc5dcc4eb61c1fafd9e271acaf5149 Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 10:59:53 -0500 Subject: [PATCH 373/593] use === since it's comparing primitives --- test/spec/spec-line-chart.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index f6c4bc17..1daa7a3c 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -25,8 +25,8 @@ describe('Line chart tests', function () { }); chart.on('created', function () { - expect($('.ct-point').eq(0).attr('ct:value')).toEqual('1,2'); - expect($('.ct-point').eq(1).attr('ct:value')).toEqual('3,4'); + expect($('.ct-point').eq(0).attr('ct:value')).toBe('1,2'); + expect($('.ct-point').eq(1).attr('ct:value')).toBe('3,4'); done(); }); }); @@ -47,9 +47,9 @@ describe('Line chart tests', function () { }); chart.on('created', function () { - expect($('.ct-point').eq(0).attr('ct:value')).toEqual('0,1'); - expect($('.ct-point').eq(1).attr('ct:value')).toEqual('1,0'); - expect($('.ct-point').eq(2).attr('ct:value')).toEqual('0,0'); + expect($('.ct-point').eq(0).attr('ct:value')).toBe('0,1'); + expect($('.ct-point').eq(1).attr('ct:value')).toBe('1,0'); + expect($('.ct-point').eq(2).attr('ct:value')).toBe('0,0'); done(); }); }); From eacab59de08b78758bd57f046f6e7a592e640721 Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 11:13:24 -0500 Subject: [PATCH 374/593] ensure ct:value has values that are zero --- src/scripts/charts/bar.js | 2 +- test/spec/spec-bar-chart.js | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 77e73853..23c81247 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -347,7 +347,7 @@ // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'value': [value.x, value.y].filter(function(v) { - return v; + return v || v === 0; }).join(','), 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); diff --git a/test/spec/spec-bar-chart.js b/test/spec/spec-bar-chart.js index e110b7a0..026dab47 100644 --- a/test/spec/spec-bar-chart.js +++ b/test/spec/spec-bar-chart.js @@ -9,6 +9,52 @@ describe('Bar chart tests', function() { }); + describe('ct:value attribute', function() { + it('should contain x and y value for each bar', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', { + series: [[ + {x: 1, y: 2}, + {x: 3, y: 4} + ]] + }, { + axisX: { + type: Chartist.AutoScaleAxis + } + }); + + chart.on('created', function() { + expect($('.ct-bar').eq(0).attr('ct:value')).toEqual('1,2'); + expect($('.ct-bar').eq(1).attr('ct:value')).toEqual('3,4'); + done(); + }); + }); + + it('should render values that are zero', function(done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', { + series: [[ + {x: 0, y: 1}, + {x: 2, y: 0}, + {x: 0, y: 0} + ]] + }, { + axisX: { + type: Chartist.AutoScaleAxis + } + }); + + chart.on('created', function() { + expect($('.ct-bar').eq(0).attr('ct:value')).toEqual('0,1'); + expect($('.ct-bar').eq(1).attr('ct:value')).toEqual('2,0'); + expect($('.ct-bar').eq(2).attr('ct:value')).toEqual('0,0'); + done(); + }); + }); + }); + describe('Meta data tests', function () { it('should render meta data correctly with mixed value array', function(done) { jasmine.getFixtures().set('
    '); From 2d8cf80591468f81a8cd2d4cd8f3e6d6d8511234 Mon Sep 17 00:00:00 2001 From: Paul Salaets Date: Sat, 23 Jan 2016 11:20:04 -0500 Subject: [PATCH 375/593] use helper to filter out non-numbers --- src/scripts/charts/bar.js | 4 +--- src/scripts/charts/line.js | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 23c81247..6429d56e 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -346,9 +346,7 @@ // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': [value.x, value.y].filter(function(v) { - return v || v === 0; - }).join(','), + 'value': [value.x, value.y].filter(Chartist.isNum).join(','), 'meta': Chartist.getMetaData(series, valueIndex) }, Chartist.xmlNs.uri); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index afe8437b..2ec06d42 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -205,9 +205,7 @@ x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { - return v || v === 0; - }).join(','), + 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), 'meta': pathElement.data.meta }, Chartist.xmlNs.uri); From eb56a3a6b896db8ffa30aef65d674a791f1a98bf Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:17:56 +0100 Subject: [PATCH 376/593] Removed workaround and fallback for SVG element width and height calculations, fixes #592 --- src/scripts/svg.js | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index c31a67b0..0256ab4b 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -311,43 +311,23 @@ } /** - * "Save" way to get property value from svg BoundingBox. - * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node. - * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/) - * - * @memberof Chartist.Svg - * @param {SVGElement} node The svg node to - * @param {String} prop The property to fetch (ex.: height, width, ...) - * @returns {Number} The value of the given bbox property - */ - function getBBoxProperty(node, prop) { - try { - return node.getBBox()[prop]; - } catch(e) {} - - return 0; - } - - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element height using `getBoundingClientRect` * * @memberof Chartist.Svg * @return {Number} The elements height in pixels */ function height() { - return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight; + return this._node.getBoundingClientRect().height; } /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element width using `getBoundingClientRect` * * @memberof Chartist.Core * @return {Number} The elements width in pixels */ function width() { - return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth; + return this._node.getBoundingClientRect().width; } /** From 941cd1426e72c37d9f642aabcac6c2a15dbfd19a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:27:05 +0100 Subject: [PATCH 377/593] Removed serialization of values on line chart areas, fixes #424 --- src/scripts/charts/line.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 2ec06d42..c37f1bc7 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -281,9 +281,7 @@ // and adding the created DOM elements to the correct series group var area = seriesElement.elem('path', { d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': data.normalized[seriesIndex] - }, Chartist.xmlNs.uri); + }, options.classNames.area, true); // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { From e5e3a2f7a5303267c789b1d9285590494410ac96 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:29:21 +0100 Subject: [PATCH 378/593] Removed onlyInteger setting from default bar chart settings, fixes #423 --- src/scripts/charts/bar.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 6429d56e..1320f195 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -65,8 +65,6 @@ high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, - // Use only integer values (whole numbers) for the scale steps - onlyInteger: false, // 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} chartPadding: { top: 15, From a4d7ff7e6a5f07a29077d6926153540775595298 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 11:44:13 +0100 Subject: [PATCH 379/593] Adding unminified CSS to dist output, fixes #506 --- tasks/aliases.yml | 4 ++-- tasks/copy.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tasks/aliases.yml b/tasks/aliases.yml index 0142ed10..ea64d2f5 100644 --- a/tasks/aliases.yml +++ b/tasks/aliases.yml @@ -12,13 +12,13 @@ default: # create the library build: - 'clean:dist' + - 'sass:dist' + - 'cssmin' - 'copy:dist' - 'concat:dist' - 'template:dist' - 'umd' - 'uglify:dist' - - 'sass:dist' - - 'cssmin' # prepare the website public: diff --git a/tasks/copy.js b/tasks/copy.js index 3b99c9cc..ec2c28f8 100644 --- a/tasks/copy.js +++ b/tasks/copy.js @@ -55,6 +55,12 @@ module.exports = function (grunt) { '*.scss' ] }, + { + expand: true, + cwd: '.tmp/styles', + dest: '<%= pkg.config.dist %>/', + src: 'chartist.css*' + }, { dest: '<%= pkg.config.dist %>/', src: 'LICENSE' From 38ab68f1309a90cd418cc595f557409b2bade5c4 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 24 Jan 2016 21:07:38 +0100 Subject: [PATCH 380/593] Allow charts to be created without data and labels, fixes #598, fixes #588, fixes #537, fixes #425 --- src/scripts/axes/axis.js | 2 +- src/scripts/charts/bar.js | 3 +- src/scripts/charts/line.js | 1 + src/scripts/charts/pie.js | 5 +- src/scripts/core.js | 41 ++++++++++- test/spec/spec-bar-chart.js | 133 +++++++++++++++++++++++++++++++++++ test/spec/spec-line-chart.js | 90 ++++++++++++++++++++++++ 7 files changed, 270 insertions(+), 5 deletions(-) diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 4ea910a5..bca56876 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -56,7 +56,7 @@ } // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!labelValues[index] && labelValues[index] !== 0) { + if(!Chartist.isFalseyButZero(labelValues[index]) && !labelValues[index] === '') { return; } diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 1320f195..673c8acd 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -107,6 +107,7 @@ * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { @@ -129,7 +130,7 @@ var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); - if(options.stackBars) { + if(options.stackBars && data.normalized.length !== 0) { // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index c37f1bc7..5fa8d9dd 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -111,6 +111,7 @@ * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: Chartist.getDataArray(this.data, options.reverseData, true) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 8a57bb78..b22cfef9 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -81,6 +81,7 @@ * @param options */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var seriesGroups = [], labelsGroup, chartRect, @@ -166,7 +167,7 @@ // Use slight offset so there are no transparent hairline issues var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); - + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees if(endAngle - overlappigStartAngle >= 359.99) { @@ -226,7 +227,7 @@ if(options.showLabel) { // Position at the labelRadius distance from center and between start and end angle var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { diff --git a/src/scripts/core.js b/src/scripts/core.js index 96d2b6eb..e403e1d5 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -309,6 +309,44 @@ var Chartist = { return svg; }; + /** + * Ensures that the data object passed as second argument to the charts is present and correctly initialized. + * + * @param {Object} data The data object that is passed as second argument to the charts + * @return {Object} The normalized data object + */ + Chartist.normalizeData = function(data) { + // Ensure data is present otherwise enforce + data = data || {series: [], labels: []}; + data.series = data.series || []; + data.labels = data.labels || []; + + // Check if we should generate some labels based on existing series data + if (data.series.length > 0 && data.labels.length === 0) { + var normalized = Chartist.getDataArray(data), + labelCount; + + // If all elements of the normalized data array are arrays we're dealing with + // data from Bar or Line charts and we need to find the largest series if they are un-even + if (normalized.every(function(value) { + return value instanceof Array; + })) { + // Getting the series with the the most elements + labelCount = Math.max.apply(null, normalized.map(function(series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = normalized.length; + } + + // Setting labels to an array with emptry strings using our labelCount estimated above + data.labels = Chartist.times(labelCount).map(function() { + return ''; + }); + } + return data; + }; /** * Reverses the series, labels and series data arrays. @@ -516,7 +554,8 @@ var Chartist = { highLow.low = 0; } else { // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors - highLow.high = highLow.low = 0; + highLow.high = 1; + highLow.low = 0; } } diff --git a/test/spec/spec-bar-chart.js b/test/spec/spec-bar-chart.js index 026dab47..c726c4f7 100644 --- a/test/spec/spec-bar-chart.js +++ b/test/spec/spec-bar-chart.js @@ -141,4 +141,137 @@ describe('Bar chart tests', function() { }); }); }); + + describe('Empty data tests', function () { + it('should render empty grid with no data', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart'); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with only labels', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + labels: [1, 2, 3, 4] + }; + var chart = new Chartist.Bar('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Find exactly as many horizontal grid lines as labels were specified (Step Axis) + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(data.labels.length); + done(); + }); + }); + + it('should generate labels and render empty grid with only series in data', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + series: [ + [1, 2, 3, 4], + [2, 3, 4], + [3, 4] + ] + }; + var chart = new Chartist.Bar('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Should generate the labels using the largest series count + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(Math.max.apply(null, data.series.map(function(series) { + return series.length; + }))); + done(); + }); + }); + + it('should render empty grid with no data and specified high low', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + width: 400, + height: 300, + high: 100, + low: -100 + }); + + chart.on('created', function () { + // Find first and last label + var labels = document.querySelectorAll('.ct-labels .ct-label.ct-vertical'); + var firstLabel = labels[0]; + var lastLabel = labels[labels.length - 1]; + + expect(firstLabel.textContent).toBe('-100'); + expect(lastLabel.textContent).toBe('100'); + done(); + }); + }); + + it('should render empty grid with no data and reverseData option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + reverseData: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and stackBars option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + stackBars: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and horizontalBars option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + horizontalBars: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + // TODO: In theory the axis should be created with ct-horizontal class + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and distributeSeries option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Bar('.ct-chart', null, { + distributeSeries: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + }); }); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index 1daa7a3c..b4cf31fe 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -313,4 +313,94 @@ describe('Line chart tests', function () { }); }); }); + + describe('Empty data tests', function () { + it('should render empty grid with no data', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart'); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with only labels', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + labels: [1, 2, 3, 4] + }; + var chart = new Chartist.Line('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Find exactly as many horizontal grid lines as labels were specified (Step Axis) + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(data.labels.length); + done(); + }); + }); + + it('should generate labels and render empty grid with only series in data', function (done) { + jasmine.getFixtures().set('
    '); + + var data = { + series: [ + [1, 2, 3, 4], + [2, 3, 4], + [3, 4] + ] + }; + var chart = new Chartist.Line('.ct-chart', data); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Should generate the labels using the largest series count + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(Math.max.apply(null, data.series.map(function(series) { + return series.length; + }))); + done(); + }); + }); + + it('should render empty grid with no data and specified high low', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', null, { + width: 400, + height: 300, + high: 100, + low: -100 + }); + + chart.on('created', function () { + // Find first and last label + var labels = document.querySelectorAll('.ct-labels .ct-label.ct-vertical'); + var firstLabel = labels[0]; + var lastLabel = labels[labels.length - 1]; + + expect(firstLabel.textContent).toBe('-100'); + expect(lastLabel.textContent).toBe('100'); + done(); + }); + }); + + it('should render empty grid with no data and reverseData option', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', null, { + reverseData: true + }); + + chart.on('created', function () { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + }); }); From e5d460234895c37a2ffcac2e4df54fd89af15932 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 21 Feb 2016 09:42:40 +0100 Subject: [PATCH 381/593] Added nvmrc file with currently used node version --- .nvmrc | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..7fd9b020 --- /dev/null +++ b/.nvmrc @@ -0,0 +1,2 @@ +v0.10.35 + From 5bfcffb3d5216ce5554d4a43bd145a3e1828563b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 21 Feb 2016 10:29:41 +0100 Subject: [PATCH 382/593] Refactored namespaced attribute handling, fixes #584 --- src/scripts/charts/bar.js | 12 ++++++------ src/scripts/charts/line.js | 12 ++++++------ src/scripts/charts/pie.js | 10 +++++----- src/scripts/core.js | 16 +++++++++++++++- src/scripts/svg.js | 25 +++++++++---------------- test/spec/spec-svg.js | 19 +++++++++++++++++++ 6 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 673c8acd..0e3c7fa4 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -254,9 +254,9 @@ // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -345,9 +345,9 @@ // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': [value.x, value.y].filter(Chartist.isNum).join(','), - 'meta': Chartist.getMetaData(series, valueIndex) - }, Chartist.xmlNs.uri); + 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','), + 'ct:meta': Chartist.getMetaData(series, valueIndex) + }); this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 5fa8d9dd..8c92c938 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -154,9 +154,9 @@ // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -206,9 +206,9 @@ x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), - 'meta': pathElement.data.meta - }, Chartist.xmlNs.uri); + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), + 'ct:meta': pathElement.data.meta + }); this.eventEmitter.emit('draw', { type: 'point', diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index b22cfef9..091b35ff 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -154,8 +154,8 @@ // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[i].attr({ - 'series-name': series.name - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name + }); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -195,9 +195,9 @@ // Adding the pie series value to the path pathElement.attr({ - 'value': dataArray[i], - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:value': dataArray[i], + 'ct:meta': Chartist.serialize(series.meta) + }); // If this is a donut, we add the stroke-width as style attribute if(options.donut) { diff --git a/src/scripts/core.js b/src/scripts/core.js index e403e1d5..c1b1d587 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -10,6 +10,20 @@ var Chartist = { (function (window, document, Chartist) { 'use strict'; + /** + * This object contains all namespaces used within Chartist. + * + * @memberof Chartist.Core + * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}} + */ + Chartist.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' + }; + /** * Helps to simplify functional style code * @@ -290,7 +304,7 @@ var Chartist = { // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttributeNS('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix); + return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct'); }).forEach(function removePreviousElement(svg) { container.removeChild(svg); }); diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 0256ab4b..be20ade4 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -7,16 +7,6 @@ (function(window, document, Chartist) { 'use strict'; - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; - - Chartist.xmlNs = { - qualifiedName: 'xmlns:ct', - prefix: 'ct', - uri: 'http://gionkunz.github.com/chartist-js/ct' - }; - /** * 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. * @@ -33,11 +23,13 @@ if(name instanceof Element) { this._node = name; } else { - this._node = document.createElementNS(svgNs, name); + this._node = document.createElementNS(Chartist.namespaces.svg, name); // If this is an SVG element created then custom namespace if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + this.attr({ + 'xmlns:ct': Chartist.namespaces.ct + }); } } @@ -63,7 +55,7 @@ * * @memberof Chartist.Svg * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @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. * @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. */ function attr(attributes, ns) { @@ -81,8 +73,9 @@ return; } - if(ns) { - this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + if (key.indexOf(':') !== -1) { + var namespacedAttribute = key.split(':'); + this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]); } else { this._node.setAttribute(key, attributes[key]); } @@ -173,7 +166,7 @@ } // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); + content.setAttribute('xmlns', Chartist.namespaces.xmlns); // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) diff --git a/test/spec/spec-svg.js b/test/spec/spec-svg.js index f997242d..0abfa8ec 100644 --- a/test/spec/spec-svg.js +++ b/test/spec/spec-svg.js @@ -65,6 +65,25 @@ describe('Chartist SVG', function () { expect(svg._node.firstChild.attributes.r.textContent).toBe('10'); }); + it('should allow to set namespaced attributes', function () { + var svg = new window.Chartist.Svg('image'); + svg.elem('image').attr({ + x: 100, + y: 100, + height: 100, + width: 100, + 'xlink:href': 'image.jpg' + }); + + expect(svg._node).toBeDefined(); + expect(svg._node.firstChild).toBeDefined(); + expect(svg._node.firstChild.getAttribute('x')).toBe('100'); + expect(svg._node.firstChild.getAttribute('y')).toBe('100'); + expect(svg._node.firstChild.getAttribute('width')).toBe('100'); + expect(svg._node.firstChild.getAttribute('height')).toBe('100'); + expect(svg._node.firstChild.getAttributeNS(Chartist.namespaces.xlink, 'href')).toBe('image.jpg'); + }); + it('should clear on each nesting level', function () { var svg = new window.Chartist.Svg('svg'); var group = svg.elem('g'); From 2d92bf55cbf7efe3e69457655f422fe207fa7a05 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 21 Feb 2016 10:46:31 +0100 Subject: [PATCH 383/593] Added dual licensing WTFPL and MIT, built new version --- LICENSE-MIT | 7 + LICENSE => LICENSE-WTFPL | 2 +- dist/LICENSE | 13 - dist/chartist.css | 592 +++++++++++++++++++++++++++++++++++++++ dist/chartist.css.map | 11 + dist/chartist.js | 211 ++++++++------ dist/chartist.min.js | 13 +- dist/chartist.min.js.map | 2 +- package.json | 10 +- 9 files changed, 750 insertions(+), 111 deletions(-) create mode 100644 LICENSE-MIT rename LICENSE => LICENSE-WTFPL (89%) delete mode 100644 dist/LICENSE create mode 100644 dist/chartist.css create mode 100644 dist/chartist.css.map diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..976cde6e --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,7 @@ +Copyright (c) 2013 Gion Kunz + +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: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE b/LICENSE-WTFPL similarity index 89% rename from LICENSE rename to LICENSE-WTFPL index 5c93f456..792ed5b9 100644 --- a/LICENSE +++ b/LICENSE-WTFPL @@ -1,7 +1,7 @@ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 - Copyright (C) 2004 Sam Hocevar + Copyright (c) 2013 Gion Kunz Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long diff --git a/dist/LICENSE b/dist/LICENSE deleted file mode 100644 index 5c93f456..00000000 --- a/dist/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/dist/chartist.css b/dist/chartist.css new file mode 100644 index 00000000..8f06df02 --- /dev/null +++ b/dist/chartist.css @@ -0,0 +1,592 @@ +.ct-label { + fill: rgba(0, 0, 0, 0.4); + color: rgba(0, 0, 0, 0.4); + font-size: 0.75rem; + line-height: 1; } + +.ct-chart-line .ct-label, .ct-chart-bar .ct-label { + display: block; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; } + +.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, 0.2); + stroke-width: 1px; + stroke-dasharray: 2px; } + +.ct-point { + stroke-width: 10px; + stroke-linecap: round; } + +.ct-line { + fill: none; + stroke-width: 4px; } + +.ct-area { + stroke: none; + fill-opacity: 0.1; } + +.ct-bar { + fill: none; + stroke-width: 10px; } + +.ct-slice-donut { + fill: none; + stroke-width: 60px; } + +.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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .ct-double-octave > svg { + display: block; + position: absolute; + top: 0; + left: 0; } + +/*# sourceMappingURL=chartist.css.map */ \ No newline at end of file diff --git a/dist/chartist.css.map b/dist/chartist.css.map new file mode 100644 index 00000000..d1353ddc --- /dev/null +++ b/dist/chartist.css.map @@ -0,0 +1,11 @@ +{ + "version": 3, + "file": "chartist.css", + "sources": [ + "../../chartist.scss", + "../../settings/_chartist-settings.scss" + ], + "sourcesContent": [], + "mappings": "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", + "names": [] +} \ No newline at end of file diff --git a/dist/chartist.js b/dist/chartist.js index 5588129e..497d2d8e 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,10 +14,11 @@ } }(this, function () { -/* Chartist.js 0.9.5 - * Copyright © 2015 Gion Kunz - * Free to use under the WTFPL license. - * http://www.wtfpl.net/ +/* Chartist.js 0.9.6 + * Copyright © 2016 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 */ /** * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. @@ -25,12 +26,26 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.5' + version: '0.9.6' }; (function (window, document, Chartist) { 'use strict'; + /** + * This object contains all namespaces used within Chartist. + * + * @memberof Chartist.Core + * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}} + */ + Chartist.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' + }; + /** * Helps to simplify functional style code * @@ -311,7 +326,7 @@ var Chartist = { // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttributeNS('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix); + return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct'); }).forEach(function removePreviousElement(svg) { container.removeChild(svg); }); @@ -330,6 +345,44 @@ var Chartist = { return svg; }; + /** + * Ensures that the data object passed as second argument to the charts is present and correctly initialized. + * + * @param {Object} data The data object that is passed as second argument to the charts + * @return {Object} The normalized data object + */ + Chartist.normalizeData = function(data) { + // Ensure data is present otherwise enforce + data = data || {series: [], labels: []}; + data.series = data.series || []; + data.labels = data.labels || []; + + // Check if we should generate some labels based on existing series data + if (data.series.length > 0 && data.labels.length === 0) { + var normalized = Chartist.getDataArray(data), + labelCount; + + // If all elements of the normalized data array are arrays we're dealing with + // data from Bar or Line charts and we need to find the largest series if they are un-even + if (normalized.every(function(value) { + return value instanceof Array; + })) { + // Getting the series with the the most elements + labelCount = Math.max.apply(null, normalized.map(function(series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = normalized.length; + } + + // Setting labels to an array with emptry strings using our labelCount estimated above + data.labels = Chartist.times(labelCount).map(function() { + return ''; + }); + } + return data; + }; /** * Reverses the series, labels and series data arrays. @@ -532,9 +585,13 @@ var Chartist = { } else if (highLow.low < 0) { // If we have the same negative value for the bounds we set bounds.high to 0 highLow.high = 0; - } else { + } else if (highLow.high > 0) { // If we have the same positive value for the bounds we set bounds.low to 0 highLow.low = 0; + } else { + // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors + highLow.high = 1; + highLow.low = 0; } } @@ -1158,10 +1215,13 @@ var Chartist = { // This is necessary to treat "holes" in line charts var segments = splitIntoSegments(pathCoordinates, valueData); - // If the split resulted in more that one segment we need to interpolate each segment individually and join them - // afterwards together into a single path. - if(segments.length > 1) { - var paths = []; + if(!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return Chartist.Interpolation.none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; // For each segment we will recurse the cardinal function segments.forEach(function(segment) { paths.push(cardinal(segment.pathCoordinates, segment.valueData)); @@ -1677,16 +1737,6 @@ var Chartist = { (function(window, document, Chartist) { 'use strict'; - var svgNs = 'http://www.w3.org/2000/svg', - xmlNs = 'http://www.w3.org/2000/xmlns/', - xhtmlNs = 'http://www.w3.org/1999/xhtml'; - - Chartist.xmlNs = { - qualifiedName: 'xmlns:ct', - prefix: 'ct', - uri: 'http://gionkunz.github.com/chartist-js/ct' - }; - /** * 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. * @@ -1703,11 +1753,13 @@ var Chartist = { if(name instanceof Element) { this._node = name; } else { - this._node = document.createElementNS(svgNs, name); + this._node = document.createElementNS(Chartist.namespaces.svg, name); // If this is an SVG element created then custom namespace if(name === 'svg') { - this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri); + this.attr({ + 'xmlns:ct': Chartist.namespaces.ct + }); } } @@ -1733,7 +1785,7 @@ var Chartist = { * * @memberof Chartist.Svg * @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. - * @param {String} ns If specified, the attributes will be set as namespace attributes with ns as prefix. + * @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. * @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. */ function attr(attributes, ns) { @@ -1751,8 +1803,9 @@ var Chartist = { return; } - if(ns) { - this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), attributes[key]); + if (key.indexOf(':') !== -1) { + var namespacedAttribute = key.split(':'); + this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]); } else { this._node.setAttribute(key, attributes[key]); } @@ -1843,7 +1896,7 @@ var Chartist = { } // Adding namespace to content element - content.setAttribute('xmlns', xhtmlNs); + content.setAttribute('xmlns', Chartist.namespaces.xmlns); // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) @@ -1981,43 +2034,23 @@ var Chartist = { } /** - * "Save" way to get property value from svg BoundingBox. - * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node. - * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/) - * - * @memberof Chartist.Svg - * @param {SVGElement} node The svg node to - * @param {String} prop The property to fetch (ex.: height, width, ...) - * @returns {Number} The value of the given bbox property - */ - function getBBoxProperty(node, prop) { - try { - return node.getBBox()[prop]; - } catch(e) {} - - return 0; - } - - /** - * Get element height with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element height using `getBoundingClientRect` * * @memberof Chartist.Svg * @return {Number} The elements height in pixels */ function height() { - return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight; + return this._node.getBoundingClientRect().height; } /** - * Get element width with fallback to svg BoundingBox or parent container dimensions: - * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985) + * Get element width using `getBoundingClientRect` * * @memberof Chartist.Core * @return {Number} The elements width in pixels */ function width() { - return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth; + return this._node.getBoundingClientRect().width; } /** @@ -2725,7 +2758,7 @@ var Chartist = { } // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!labelValues[index] && labelValues[index] !== 0) { + if(!Chartist.isFalseyButZero(labelValues[index]) && !labelValues[index] === '') { return; } @@ -3042,6 +3075,7 @@ var Chartist = { * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: Chartist.getDataArray(this.data, options.reverseData, true) @@ -3084,9 +3118,9 @@ var Chartist = { // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -3136,11 +3170,9 @@ var Chartist = { x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) { - return v; - }).join(','), - 'meta': pathElement.data.meta - }, Chartist.xmlNs.uri); + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), + 'ct:meta': pathElement.data.meta + }); this.eventEmitter.emit('draw', { type: 'point', @@ -3214,9 +3246,7 @@ var Chartist = { // and adding the created DOM elements to the correct series group var area = seriesElement.elem('path', { d: areaPath.stringify() - }, options.classNames.area, true).attr({ - 'values': data.normalized[seriesIndex] - }, Chartist.xmlNs.uri); + }, options.classNames.area, true); // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { @@ -3410,8 +3440,6 @@ var Chartist = { high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, - // Use only integer values (whole numbers) for the scale steps - onlyInteger: false, // 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} chartPadding: { top: 15, @@ -3454,6 +3482,7 @@ var Chartist = { * */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var data = { raw: this.data, normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { @@ -3476,15 +3505,15 @@ var Chartist = { var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); - if(options.stackBars) { + if(options.stackBars && data.normalized.length !== 0) { // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { return value; }).reduce(function(prev, curr) { return { - x: prev.x + curr.x || 0, - y: prev.y + curr.y || 0 + x: prev.x + (curr && curr.x) || 0, + y: prev.y + (curr && curr.y) || 0 }; }, {x: 0, y: 0}); }); @@ -3600,9 +3629,9 @@ var Chartist = { // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ - 'series-name': series.name, - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name, + 'ct:meta': Chartist.serialize(series.meta) + }); // Use series class from series data or if not set generate one seriesElement.addClass([ @@ -3691,11 +3720,9 @@ var Chartist = { // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'value': [value.x, value.y].filter(function(v) { - return v; - }).join(','), - 'meta': Chartist.getMetaData(series, valueIndex) - }, Chartist.xmlNs.uri); + 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','), + 'ct:meta': Chartist.getMetaData(series, valueIndex) + }); this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', @@ -3826,7 +3853,9 @@ var Chartist = { // 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. labelDirection: 'neutral', // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. - reverseData: false + reverseData: false, + // If true empty values will be ignored to avoid drawing unncessary slices and labels + ignoreEmptyValues: false }; /** @@ -3857,6 +3886,7 @@ var Chartist = { * @param options */ function createChart(options) { + this.data = Chartist.normalizeData(this.data); var seriesGroups = [], labelsGroup, chartRect, @@ -3921,13 +3951,16 @@ var Chartist = { // Draw the series // initialize series groups for (var i = 0; i < this.data.series.length; i++) { + // If current value is zero and we are ignoring empty values then skip to next value + if (dataArray[i] === 0 && options.ignoreEmptyValues) continue; + var series = this.data.series[i]; seriesGroups[i] = this.svg.elem('g', null, null, true); // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[i].attr({ - 'series-name': series.name - }, Chartist.xmlNs.uri); + 'ct:series-name': series.name + }); // Use series class from series data or if not set generate one seriesGroups[i].addClass([ @@ -3936,13 +3969,17 @@ var Chartist = { ].join(' ')); var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + + // Use slight offset so there are no transparent hairline issues + var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees - if(endAngle - startAngle === 360) { - endAngle -= 0.01; + if(endAngle - overlappigStartAngle >= 359.99) { + endAngle = overlappigStartAngle + 359.99; } - var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)), + var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); // 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 @@ -3963,9 +4000,9 @@ var Chartist = { // Adding the pie series value to the path pathElement.attr({ - 'value': dataArray[i], - 'meta': Chartist.serialize(series.meta) - }, Chartist.xmlNs.uri); + 'ct:value': dataArray[i], + 'ct:meta': Chartist.serialize(series.meta) + }); // If this is a donut, we add the stroke-width as style attribute if(options.donut) { @@ -3995,7 +4032,7 @@ var Chartist = { if(options.showLabel) { // Position at the labelRadius distance from center and between start and end angle var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i); + interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { @@ -4017,7 +4054,7 @@ var Chartist = { } } - // Set next startAngle to current endAngle. Use slight offset so there are no transparent hairline issues + // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; } diff --git a/dist/chartist.min.js b/dist/chartist.min.js index dfb9e726..049a22ef 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,9 +1,10 @@ -/* Chartist.js 0.9.5 - * Copyright © 2015 Gion Kunz - * Free to use under the WTFPL license. - * http://www.wtfpl.net/ +/* Chartist.js 0.9.6 + * Copyright © 2016 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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.5"};return function(a,b,c){"use strict";c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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("http://www.w3.org/2000/xmlns/",c.xmlNs.prefix)}).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.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&ck,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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(h){var k=i.elem("path",{d:h.stringify()},a.classNames.area,!0).attr({values:b.normalized[g]},c.xmlNs.uri);this.eventEmitter.emit("draw",{type:"area",values:b.normalized[g],path:h.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:k})}.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,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",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={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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){var i=c.serialMap(d.normalized,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+b.x||0,y:a.y+b.y||0}},{x:0,y:0})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"series-name":b.name,meta:c.serialize(b.meta)},c.xmlNs.uri),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({value:[g.x,g.y].filter(function(a){return a}).join(","),meta:c.getMetaData(b,k)},c.xmlNs.uri),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,onlyInteger:!1,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p180,0,s.x,s.y);a.donut||u.line(n.x,n.y);var v=j[p].elem("path",{d:u.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(v.attr({value:l[p],meta:c.serialize(q.meta)},c.xmlNs.uri),a.donut&&v.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:v,path:u.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var w=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),x=a.labelInterpolationFnc(this.data.labels?this.data.labels[p]:l[p],p);if(x||0===x){var y=b.elem("text",{dx:w.x,dy:w.y,"text-anchor":d(n,w,a.labelDirection)},a.classNames.label).text(""+x);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:y,text:""+x,x:w.x,y:w.y})}}k=r}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};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.6"};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){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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){if(a=a||{series:[],labels:[]},a.series=a.series||[],a.labels=a.labels||[],a.series.length>0&&0===a.labels.length){var b,d=c.getDataArray(a);b=d.every(function(a){return a instanceof Array})?Math.max.apply(null,d.map(function(a){return a.length})):d.length,a.labels=c.times(b).map(function(){return""})}return 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.isNum=function(a){return!isNaN(a)&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return isNaN(+a)?void 0:+a},c.getMultiValue=function(a,b){return c.isNum(a)?+a:a?a[b||"y"]||0:0},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){var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=c.orderOfMagnitude(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=c.projectLength(a,j.step,j),l=d>k,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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[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,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",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){this.data=c.normalizeData(this.data);var b,d={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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!==d.normalized.length){var i=c.serialMap(d.normalized,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})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":b.name,"ct:meta":c.serialize(b.meta)}),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNum).join(","),"ct:meta":c.getMetaData(b,k)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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){this.data=c.normalizeData(this.data);var b,e,f,h,i,j=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p=359.99&&(r=s+359.99);var t=c.polarToCartesian(n.x,n.y,f,s),u=c.polarToCartesian(n.x,n.y,f,r),v=new c.Svg.Path(!a.donut).move(u.x,u.y).arc(f,f,0,r-k>180,0,t.x,t.y);a.donut||v.line(n.x,n.y);var w=j[p].elem("path",{d:v.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(w.attr({"ct:value":l[p],"ct:meta":c.serialize(q.meta)}),a.donut&&w.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:w,path:v.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var x=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),y=a.labelInterpolationFnc(this.data.labels&&!c.isFalseyButZero(this.data.labels[p])?this.data.labels[p]:l[p],p);if(y||0===y){var z=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":d(n,x,a.labelDirection)},a.classNames.label).text(""+y);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:z,text:""+y,x:x.x,y:x.y})}}k=r}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}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index 2c87ca8c..cea4ae4c 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","svg","querySelectorAll","filter","getAttributeNS","xmlNs","prefix","removeChild","Svg","attr","addClass","style","appendChild","_node","reverseData","labels","reverse","series","i","getDataArray","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","svgNs","setAttributeNS","qualifiedName","uri","firstChild","insertBefore","ns","getAttribute","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","createElement","innerHTML","xhtmlNs","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","split","names","concat","self","removeClass","removedClasses","removeAllClasses","getBBoxProperty","getBBox","clientHeight","clientWidth","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","normalized","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","series-name","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","v","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","endAngle","sliceDonut","slicePie","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([], 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.9.5\n * Copyright © 2015 Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\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.9.5'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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('http://www.w3.org/2000/xmlns/', Chartist.xmlNs.prefix);\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 /**\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\n\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 if(segments.length > 1) {\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 * 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 // 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.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 var svgNs = 'http://www.w3.org/2000/svg',\n xmlNs = 'http://www.w3.org/2000/xmlns/',\n xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n Chartist.xmlNs = {\n qualifiedName: 'xmlns:ct',\n prefix: 'ct',\n uri: 'http://gionkunz.github.com/chartist-js/ct'\n };\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(svgNs, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this._node.setAttributeNS(xmlNs, Chartist.xmlNs.qualifiedName, Chartist.xmlNs.uri);\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 attributes will be set as namespace attributes with ns as prefix.\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(ns) {\n this._node.setAttributeNS(ns, [Chartist.xmlNs.prefix, ':', key].join(''), 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 * 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', xhtmlNs);\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 * \"Save\" way to get property value from svg BoundingBox.\n * This is a workaround. Firefox throws an NS_ERROR_FAILURE error if getBBox() is called on an invisible node.\n * See [NS_ERROR_FAILURE: Component returned failure code: 0x80004005](http://jsfiddle.net/sym3tri/kWWDK/)\n *\n * @memberof Chartist.Svg\n * @param {SVGElement} node The svg node to\n * @param {String} prop The property to fetch (ex.: height, width, ...)\n * @returns {Number} The value of the given bbox property\n */\n function getBBoxProperty(node, prop) {\n try {\n return node.getBBox()[prop];\n } catch(e) {}\n\n return 0;\n }\n\n /**\n * Get element height with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.clientHeight || Math.round(getBBoxProperty(this._node, 'height')) || this._node.parentNode.clientHeight;\n }\n\n /**\n * Get element width with fallback to svg BoundingBox or parent container dimensions:\n * See [bugzilla.mozilla.org](https://bugzilla.mozilla.org/show_bug.cgi?id=530985)\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.clientWidth || Math.round(getBBoxProperty(this._node, 'width')) || this._node.parentNode.clientWidth;\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 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(!labelValues[index] && labelValues[index] !== 0) {\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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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 'value': [pathElement.data.value.x, pathElement.data.value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': pathElement.data.meta\n }, Chartist.xmlNs.uri);\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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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).attr({\n 'values': data.normalized[seriesIndex]\n }, Chartist.xmlNs.uri);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized[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 adition 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 // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false,\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 // 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 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 raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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.x || 0,\n y: prev.y + curr.y || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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 'series-name': series.name,\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'value': [value.x, value.y].filter(function(v) {\n return v;\n }).join(','),\n 'meta': Chartist.getMetaData(series, valueIndex)\n }, Chartist.xmlNs.uri);\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 };\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 seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'series-name': series.name\n }, Chartist.xmlNs.uri);\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\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 - startAngle === 360) {\n endAngle -= 0.01;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)),\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[i].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 'value': dataArray[i],\n 'meta': Chartist.serialize(series.meta)\n }, Chartist.xmlNs.uri);\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels ? this.data.labels[i] : dataArray[i], i);\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: i,\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. Use slight offset so there are no transparent hairline issues\n // (except for last slice)\n startAngle = endAngle;\n }\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","exports","module","this","Chartist","version","window","document","namespaces","svg","xmlns","xhtml","xlink","ct","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","series","labels","labelCount","normalized","getDataArray","every","reverseData","reverse","i","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","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([], 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.9.6\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.9.6'\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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) {\n // Ensure data is present otherwise enforce\n data = data || {series: [], labels: []};\n data.series = data.series || [];\n data.labels = data.labels || [];\n\n // Check if we should generate some labels based on existing series data\n if (data.series.length > 0 && data.labels.length === 0) {\n var normalized = Chartist.getDataArray(data),\n labelCount;\n\n // If all elements of the normalized data array are arrays we're dealing with\n // data from Bar or Line charts and we need to find the largest series if they are un-even\n if (normalized.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, normalized.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 = normalized.length;\n }\n\n // Setting labels to an array with emptry strings using our labelCount estimated above\n data.labels = Chartist.times(labelCount).map(function() {\n return '';\n });\n }\n return data;\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\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 * 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 // 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.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 * 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 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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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.isNum).join(','),\n 'ct:meta': 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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[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 adition 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 // 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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),\n 'ct:meta': Chartist.getMetaData(series, valueIndex)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 this.data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;\n\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (i === 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[i].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': dataArray[i],\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);\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: i,\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 }\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/package.json b/package.json index a7705692..ed57043e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.5", + "version": "0.9.6", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { @@ -30,7 +30,11 @@ "licenses": [ { "type": "WTFPL", - "url": "https://github.com/gionkunz/chartist-js/blob/master/LICENSE" + "url": "https://github.com/gionkunz/chartist-js/blob/master/LICENSE-WTFPL" + }, + { + "type": "MIT", + "url": "https://github.com/gionkunz/chartist-js/blob/master/LICENSE-MIT" } ], "dependencies": {}, @@ -72,7 +76,7 @@ "test": "grunt test" }, "config": { - "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> Gion Kunz\n * Free to use under the WTFPL license.\n * http://www.wtfpl.net/\n */\n", + "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> 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", "src": "src", "dist": "dist", "site": "site", From 1da18379ea0a88b91139f81a1c5a8d3f4c3905c5 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 21 Feb 2016 11:11:40 +0100 Subject: [PATCH 384/593] Fixed license filter for NPM package --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ed57043e..92bdbdba 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ ], "files": [ "dist", - "LICENSE", + "LICENSE-WTFPL", + "LICENSE-MIT", "package.json", "README.md" ], From 3f8e629e61f66f7f252d65c34ac3a10cf9eeae81 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 23 Feb 2016 10:32:55 +0100 Subject: [PATCH 385/593] Fixed bug with label and grid rendering on axis, fixes #621 --- src/scripts/axes/axis.js | 2 +- test/spec/spec-axes.js | 104 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index bca56876..4920f360 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -56,7 +56,7 @@ } // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!Chartist.isFalseyButZero(labelValues[index]) && !labelValues[index] === '') { + if(Chartist.isFalseyButZero(labelValues[index]) && labelValues[index] !== '') { return; } diff --git a/test/spec/spec-axes.js b/test/spec/spec-axes.js index 4eadbdc4..8afd9dc1 100644 --- a/test/spec/spec-axes.js +++ b/test/spec/spec-axes.js @@ -1,14 +1,6 @@ describe('Axes tests', function() { 'use strict'; - beforeEach(function() { - - }); - - afterEach(function() { - - }); - describe('fixed scale axis', function () { it('should order the tick array', function() { @@ -50,4 +42,100 @@ describe('Axes tests', function() { }); + describe('axis label and grid creation', function () { + var ticks, chartRect, chartOptions, eventEmitter, gridGroup, labelGroup; + + beforeEach(function() { + eventEmitter = Chartist.EventEmitter(); + gridGroup = new Chartist.Svg('g'); + labelGroup = new Chartist.Svg('g'); + ticks = [1, 2]; + chartRect = { + padding: { + bottom: 5, + left: 10, + right: 15, + top: 15 + }, + y2: 15, + y1: 250, + x1: 50, + x2: 450, + width: function() { + return this.x2 - this.x1; + }, + height: function() { + return this.y1 - this.y2; + } + }; + + chartOptions = { + axisX: { + offset: 30, + position: 'end', + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true + }, + classNames: { + label: 'ct-label', + labelGroup: 'ct-labels', + grid: 'ct-grid', + gridGroup: 'ct-grids', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal', + start: 'ct-start', + end: 'ct-end' + } + }; + }); + + it('should skip all grid lines and labels for interpolated value of null', function() { + chartOptions.axisX.labelInterpolationFnc = function(value, index) { + return index === 0 ? null : value; + }; + + var axis = new Chartist.Axis(Chartist.Axis.units.x, chartRect, ticks, null); + axis.projectValue = function(value) { + return value; + }; + + axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); + expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(1); + expect(labelGroup.querySelectorAll('.ct-label').svgElements.length).toBe(1); + }); + + it('should skip all grid lines and labels for interpolated value of undefined', function() { + chartOptions.axisX.labelInterpolationFnc = function(value, index) { + return index === 0 ? undefined : value; + }; + + var axis = new Chartist.Axis(Chartist.Axis.units.x, chartRect, ticks, null); + axis.projectValue = function(value) { + return value; + }; + + axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); + expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(1); + expect(labelGroup.querySelectorAll('.ct-label').svgElements.length).toBe(1); + }); + + it('should include all grid lines and labels for interpolated value of empty strings', function() { + chartOptions.axisX.labelInterpolationFnc = function(value, index) { + return index === 0 ? '' : value; + }; + + var axis = new Chartist.Axis(Chartist.Axis.units.x, chartRect, ticks, null); + axis.projectValue = function(value) { + return value; + }; + + axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); + expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(2); + expect(labelGroup.querySelectorAll('.ct-label').svgElements.length).toBe(2); + }); + }); }); From 10832450cb9030b516c262a24ffbfa06e5fe0b78 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 23 Feb 2016 10:34:41 +0100 Subject: [PATCH 386/593] Version bump to 0.9.7 --- CHANGELOG.md | 19 +++++++++++++++++++ dist/chartist.js | 8 ++++---- dist/chartist.min.js | 4 ++-- dist/chartist.min.js.map | 2 +- package.json | 2 +- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c92cc31..181f1461 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +v0.9.7 - 23 Feb 2016 +-------------------- +- Fixed bug with label and grid rendering on axis, fixes #621 + +v0.9.6 - 22 Feb 2016 +-------------------- +- Added dual licensing WTFPL and MIT, built new version +- Adding unminified CSS to dist output, fixes #506 +- Refactored namespaced attribute handling, fixes #584 +- Allow charts to be created without data and labels, fixes #598, fixes #588, fixes #537, fixes #425 +- Removed onlyInteger setting from default bar chart settings, fixes #423 +- Removed serialization of values on line chart areas, fixes #424 +- Removed workaround and fallback for SVG element width and height calculations, fixes #592 +- Render 0 in ct:value attribute for line graphs +- Allow empty pie chart values to be ignored +- Fix #527 Pie render issue with small angles. +- Small fix for stacked bars with 'holes' in the data + + v0.9.5 - 14 Nov 2015 -------------------- - Added 'fillHoles' option for line graphs, which continues the line smoothly through data holes (Thanks to Joshua Warner !) diff --git a/dist/chartist.js b/dist/chartist.js index 497d2d8e..8f08a006 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.6 +/* Chartist.js 0.9.7 * Copyright © 2016 Gion Kunz * Free to use under either the WTFPL license or the MIT license. * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL @@ -26,7 +26,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.6' + version: '0.9.7' }; (function (window, document, Chartist) { @@ -2758,7 +2758,7 @@ var Chartist = { } // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) - if(!Chartist.isFalseyButZero(labelValues[index]) && !labelValues[index] === '') { + if(Chartist.isFalseyButZero(labelValues[index]) && labelValues[index] !== '') { return; } @@ -3332,7 +3332,7 @@ var Chartist = { * ] * }; * - * // In adition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. + * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. * var responsiveOptions = [ * ['screen and (min-width: 641px) and (max-width: 1024px)', { * showPoint: false, diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 049a22ef..fc39f873 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,10 +1,10 @@ -/* Chartist.js 0.9.6 +/* Chartist.js 0.9.7 * Copyright © 2016 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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.6"};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){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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){if(a=a||{series:[],labels:[]},a.series=a.series||[],a.labels=a.labels||[],a.series.length>0&&0===a.labels.length){var b,d=c.getDataArray(a);b=d.every(function(a){return a instanceof Array})?Math.max.apply(null,d.map(function(a){return a.length})):d.length,a.labels=c.times(b).map(function(){return""})}return 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.isNum=function(a){return!isNaN(a)&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return isNaN(+a)?void 0:+a},c.getMultiValue=function(a,b){return c.isNum(a)?+a:a?a[b||"y"]||0:0},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){var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=c.orderOfMagnitude(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=c.projectLength(a,j.step,j),l=d>k,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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[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,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",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){this.data=c.normalizeData(this.data);var b,d={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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!==d.normalized.length){var i=c.serialMap(d.normalized,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})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":b.name,"ct:meta":c.serialize(b.meta)}),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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]), +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.7"};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){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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){if(a=a||{series:[],labels:[]},a.series=a.series||[],a.labels=a.labels||[],a.series.length>0&&0===a.labels.length){var b,d=c.getDataArray(a);b=d.every(function(a){return a instanceof Array})?Math.max.apply(null,d.map(function(a){return a.length})):d.length,a.labels=c.times(b).map(function(){return""})}return 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.isNum=function(a){return!isNaN(a)&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return isNaN(+a)?void 0:+a},c.getMultiValue=function(a,b){return c.isNum(a)?+a:a?a[b||"y"]||0:0},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){var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=c.orderOfMagnitude(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=c.projectLength(a,j.step,j),l=d>k,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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[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,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",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){this.data=c.normalizeData(this.data);var b,d={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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!==d.normalized.length){var i=c.serialMap(d.normalized,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})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":b.name,"ct:meta":c.serialize(b.meta)}),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNum).join(","),"ct:meta":c.getMetaData(b,k)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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){this.data=c.normalizeData(this.data);var b,e,f,h,i,j=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p=359.99&&(r=s+359.99);var t=c.polarToCartesian(n.x,n.y,f,s),u=c.polarToCartesian(n.x,n.y,f,r),v=new c.Svg.Path(!a.donut).move(u.x,u.y).arc(f,f,0,r-k>180,0,t.x,t.y);a.donut||v.line(n.x,n.y);var w=j[p].elem("path",{d:v.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(w.attr({"ct:value":l[p],"ct:meta":c.serialize(q.meta)}),a.donut&&w.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:w,path:v.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var x=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),y=a.labelInterpolationFnc(this.data.labels&&!c.isFalseyButZero(this.data.labels[p])?this.data.labels[p]:l[p],p);if(y||0===y){var z=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":d(n,x,a.labelDirection)},a.classNames.label).text(""+y);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:z,text:""+y,x:x.x,y:x.y})}}k=r}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}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index cea4ae4c..54f7741d 100644 --- a/dist/chartist.min.js.map +++ b/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","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","series","labels","labelCount","normalized","getDataArray","every","reverseData","reverse","i","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","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([], 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.9.6\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.9.6'\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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) {\n // Ensure data is present otherwise enforce\n data = data || {series: [], labels: []};\n data.series = data.series || [];\n data.labels = data.labels || [];\n\n // Check if we should generate some labels based on existing series data\n if (data.series.length > 0 && data.labels.length === 0) {\n var normalized = Chartist.getDataArray(data),\n labelCount;\n\n // If all elements of the normalized data array are arrays we're dealing with\n // data from Bar or Line charts and we need to find the largest series if they are un-even\n if (normalized.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, normalized.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 = normalized.length;\n }\n\n // Setting labels to an array with emptry strings using our labelCount estimated above\n data.labels = Chartist.times(labelCount).map(function() {\n return '';\n });\n }\n return data;\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\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 * 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 // 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.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 * 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 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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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.isNum).join(','),\n 'ct:meta': 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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[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 adition 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 // 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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),\n 'ct:meta': Chartist.getMetaData(series, valueIndex)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 this.data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;\n\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (i === 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[i].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': dataArray[i],\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);\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: i,\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 }\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","exports","module","this","Chartist","version","window","document","namespaces","svg","xmlns","xhtml","xlink","ct","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","series","labels","labelCount","normalized","getDataArray","every","reverseData","reverse","i","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","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([], 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.9.7\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.9.7'\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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) {\n // Ensure data is present otherwise enforce\n data = data || {series: [], labels: []};\n data.series = data.series || [];\n data.labels = data.labels || [];\n\n // Check if we should generate some labels based on existing series data\n if (data.series.length > 0 && data.labels.length === 0) {\n var normalized = Chartist.getDataArray(data),\n labelCount;\n\n // If all elements of the normalized data array are arrays we're dealing with\n // data from Bar or Line charts and we need to find the largest series if they are un-even\n if (normalized.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, normalized.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 = normalized.length;\n }\n\n // Setting labels to an array with emptry strings using our labelCount estimated above\n data.labels = Chartist.times(labelCount).map(function() {\n return '';\n });\n }\n return data;\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\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 * 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 // 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.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 * 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 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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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.isNum).join(','),\n 'ct:meta': 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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[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 // 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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),\n 'ct:meta': Chartist.getMetaData(series, valueIndex)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 this.data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;\n\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (i === 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[i].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': dataArray[i],\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);\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: i,\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 }\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/package.json b/package.json index 92bdbdba..6a5696d9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.6", + "version": "0.9.7", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 1f2f0a9a1c029ba10c8c7a6db44aa5b05465dcb8 Mon Sep 17 00:00:00 2001 From: Jose Ignacio Date: Tue, 1 Mar 2016 11:17:39 +0100 Subject: [PATCH 387/593] prevent negative value for foreignObject width attribute --- src/scripts/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index c1b1d587..abe648ef 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -882,7 +882,7 @@ var Chartist = { positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; positionalData[axis.units.len] = length; - positionalData[axis.counterUnits.len] = axisOffset - 10; + positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10); if(useForeignObject) { // We need to set width and height explicitly to px as span will not expand with width and height being From 2dca902d796dc9e71293ea1a2267511b4d89d02b Mon Sep 17 00:00:00 2001 From: hansmaad Date: Mon, 14 Mar 2016 09:36:16 +0100 Subject: [PATCH 388/593] Update zoom plugin to 0.2.1 --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 97c5e025..d9e517ac 100755 --- a/bower.json +++ b/bower.json @@ -18,7 +18,7 @@ "chartist-plugin-axistitle": "~0.0.1", "chartist-plugin-threshold": "~0.0.1", "chartist-plugin-fill-donut": "~0.0.1", - "chartist-plugin-zoom": "~0.0.1", + "chartist-plugin-zoom": "~0.2.1", "matchMedia": "~0.2.0" }, "ignore": [ From 1b08948d34ff707dda05f4138fdd32d945e0fa26 Mon Sep 17 00:00:00 2001 From: Robin Edbom Date: Wed, 16 Mar 2016 09:29:11 +0100 Subject: [PATCH 389/593] Update simple-start-fixed-chart.js It says Line in the comment, the prev chart was a line so I guess this was a typo. BTW, nice Jobbs! --- site/code-snippets/simple-start-fixed-chart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/code-snippets/simple-start-fixed-chart.js b/site/code-snippets/simple-start-fixed-chart.js index 870130e7..711ee5df 100644 --- a/site/code-snippets/simple-start-fixed-chart.js +++ b/site/code-snippets/simple-start-fixed-chart.js @@ -17,4 +17,4 @@ var options = { // Create a new line chart object where as first parameter we pass in a selector // that is resolving to our chart container element. The Second parameter // is the actual data object. As a third parameter we pass in our custom options. -new Chartist.Bar('.ct-chart', data, options); \ No newline at end of file +new Chartist.Line('.ct-chart', data, options); From d424619b44df1e678aa060bd55d09632b6a33e1d Mon Sep 17 00:00:00 2001 From: hansmaad Date: Fri, 18 Mar 2016 13:36:22 +0100 Subject: [PATCH 390/593] Update grunt-sass to 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a5696d9..6844ca79 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "grunt-contrib-watch": "^0.6.1", "grunt-critical": "0.1.1", "grunt-newer": "^1.1.0", - "grunt-sass": "^0.18.0", + "grunt-sass": "^1.1.0", "grunt-svgmin": "~2.0.0", "grunt-template": "^0.2.3", "grunt-umd": "~2.3.1", From e38aa2757d502431d3ecd7e09770249a4d42d4da Mon Sep 17 00:00:00 2001 From: hansmaad Date: Fri, 18 Mar 2016 14:59:23 +0100 Subject: [PATCH 391/593] Add unit tests for Chartist.getBounds --- test/spec/spec-core.js | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 2f26b4c6..8d1b3546 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -302,4 +302,91 @@ describe('Chartist core', function() { }); }); + + describe('getBounds', function() { + + it('should return 10 steps', function() { + var bounds = Chartist.getBounds(100, { high: 10, low: 1 }, 10, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(10); + expect(bounds.values).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it('should return 5 steps', function() { + var bounds = Chartist.getBounds(100, { high: 10, low: 1 }, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(10); + expect(bounds.values).toEqual([1, 3, 5, 7, 9]); + // Is this correct behaviour? Should it include 10? + }); + + it('should return non integer steps', function() { + var bounds = Chartist.getBounds(100, { high: 2, low: 1 }, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(2); + expect(bounds.values).toEqual([ 1, 1.25, 1.5, 1.75, 2 ]); + }); + + it('should return integer steps only', function() { + var bounds = Chartist.getBounds(100, { high: 3, low: 1 }, 20, true); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(3); + expect(bounds.values).toEqual([ 1, 2, 3 ]); + }); + + it('should return single integer step', function() { + var bounds = Chartist.getBounds(100, { high: 2, low: 1 }, 20, true); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(2); + expect(bounds.values).toEqual([ 1, 2,]); + }); + + it('should floor/ceil min/max', function() { + var bounds = Chartist.getBounds(100, { high: 9.9, low: 1.01 }, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(10); + expect(bounds.values).toEqual([1, 3, 5, 7, 9]); + // Is this correct behaviour? Should it include 10? + }); + + it('should floor/ceil min/max for non integers', function() { + var bounds = Chartist.getBounds(100, { high: 2.9, low: 1.01 }, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(3); + expect(bounds.values).toEqual([1, 1.5, 2, 2.5, 3]); + }); + + it('should floor/ceil min/max if integers only', function() { + var bounds = Chartist.getBounds(100, { high: 2.9, low: 1.01 }, 20, true); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(3); + expect(bounds.values).toEqual([1, 2, 3]); + }); + + it('should return neg and pos values', function() { + var bounds = Chartist.getBounds(100, { high: 1.9, low: -0.9 }, 20, false); + expect(bounds.min).toBe(-1); + expect(bounds.max).toBe(2); + expect(bounds.values).toEqual([-1, 0, 1, 2]); + }); + + it('should return two steps if no space', function() { + var bounds = Chartist.getBounds(100, { high: 5, low: 0 }, 45, false); + expect(bounds.min).toBe(0); + expect(bounds.max).toBe(5); + expect(bounds.values).toEqual([0, 4]); + // Is this correct behaviour? Should it be [0, 5]? + }); + + it('should return single step if no space', function() { + var bounds = Chartist.getBounds(100, { high: 5, low: 0 }, 80, false); + expect(bounds.min).toBe(0); + expect(bounds.max).toBe(5); + expect(bounds.values).toEqual([0]); + // Is this correct behaviour? Should it be [0, 5]? + }); + + }); + + }); From bfdc8f26173a2b05b3ce38f2987f6763040e24c5 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Fri, 18 Mar 2016 15:02:04 +0100 Subject: [PATCH 392/593] Fix #643 Prevent infinite loop in getBounds if bounds.valueRange is very small. Add check for bounds.step to be greater than EPSILON. --- src/scripts/core.js | 13 +++++++++---- test/spec/spec-core.js | 9 +++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index cb28e755..7c3b4d3e 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -727,6 +727,10 @@ var Chartist = { } } + // step must not be less than EPSILON to create values that can be represented as floating number. + var EPSILON = 2.221E-16; + bounds.step = Math.max(bounds.step, EPSILON); + // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; @@ -740,11 +744,12 @@ var Chartist = { bounds.max = newMax; bounds.range = bounds.max - bounds.min; - bounds.values = []; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - bounds.values.push(Chartist.roundWithPrecision(i)); + var values = []; + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + var value = Chartist.roundWithPrecision(i); + value != values[values.length - 1] && values.push(i); } - + bounds.values = values; return bounds; }; diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 8d1b3546..e28a3a1e 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -385,6 +385,15 @@ describe('Chartist core', function() { expect(bounds.values).toEqual([0]); // Is this correct behaviour? Should it be [0, 5]? }); + + it('should return single step if range is less than epsilon', function() { + var bounds = Chartist.getBounds(100, { high: 1.0000000000000002, low: 1 }, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(1.0000000000000002); + expect(bounds.low).toBe(1); + expect(bounds.high).toBe(1.0000000000000002); + expect(bounds.values).toEqual([1]); + }); }); From a724ac54ee1084d8ca5228072ff6e4fc31c40e32 Mon Sep 17 00:00:00 2001 From: Jacob Quant Date: Thu, 24 Mar 2016 15:50:16 -0500 Subject: [PATCH 393/593] Added 'license' property to package.json (use of 'licenses' is deprecated) --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6844ca79..462dbfa1 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "style": "dist/chartist.min.css", "main": "dist/chartist.js", "browser": "dist/chartist.js", + "license": "MIT OR WTFPL", "licenses": [ { "type": "WTFPL", From ffddd25c8e74084ad73a67d009f5b31537be09a5 Mon Sep 17 00:00:00 2001 From: James Watmuff Date: Mon, 29 Feb 2016 17:42:05 +1100 Subject: [PATCH 394/593] Monotone cubic interpolation --- src/scripts/interpolation.js | 168 +++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 2c38f7b5..362f8b9b 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -268,6 +268,174 @@ }; }; + /** + * 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. + * + * 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`. + * + * 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. + * + * All smoothing functions within Chartist are factory functions that accept an options parameter. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.monotoneCubic({ + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the monotoneCubic factory function. + * @return {Function} + */ + Chartist.Interpolation.monotoneCubic = function(options) { + var defaultOptions = { + fillHoles: false + }; + + options = Chartist.extend({}, defaultOptions, options); + + // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates + // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards. + // This functionality is necessary to treat "holes" in the line charts + function splitIntoSegments(pathCoordinates, valueData) { + var segments = []; + var hole = true; + + for(var i = 0; i < pathCoordinates.length; i += 2) { + // If this value is a "hole" we set the hole flag + if(valueData[i / 2].value === undefined) { + if(!options.fillHoles) { + hole = true; + } + } else if(i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) { + // Because we are doing monotone interpolation, curve fitting only makes sense for + // increasing x values. Therefore if two subsequent points have the same x value, or + // the x value is decreasing, then we create a hole at this point. (Which cannot be + // filled in even with the 'fillHoles' option) + + hole = true; + } else { + // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment + if(hole) { + segments.push({ + pathCoordinates: [], + valueData: [] + }); + // As we have a valid value now, we are not in a "hole" anymore + hole = false; + } + + // Add to the segment pathCoordinates and valueData + segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); + segments[segments.length - 1].valueData.push(valueData[i / 2]); + } + } + + return segments; + } + + return function monotoneCubic(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = splitIntoSegments(pathCoordinates, valueData); + + if(!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return Chartist.Interpolation.none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; + // For each segment we will recurse the monotoneCubic fn function + segments.forEach(function(segment) { + paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return Chartist.Svg.Path.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; + + // If less than three points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return Chartist.Interpolation.none()(pathCoordinates, valueData); + } + + var xs = [], + ys = [], + i, + n = pathCoordinates.length / 2, + ms = [], + ds = [], dys = [], dxs = [], + path; + + // Populate x and y coordinates into separate arrays, for readability + + for(i = 0; i < n; i++) { + xs[i] = pathCoordinates[i * 2]; + ys[i] = pathCoordinates[i * 2 + 1]; + } + + // Calculate deltas and derivative + + for(i = 0; i < n - 1; i++) { + dys[i] = ys[i + 1] - ys[i]; + dxs[i] = xs[i + 1] - xs[i]; + ds[i] = dys[i] / dxs[i]; + } + + // Determine desired slope (m) at each point using Fritsch-Carlson method + // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation + + ms[0] = ds[0]; + ms[n - 1] = ds[n - 2]; + + for(i = 1; i < n - 1; i++) { + if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) { + ms[i] = 0; + } else { + ms[i] = 3 * (dxs[i - 1] + dxs[i]) / ( + (2 * dxs[i] + dxs[i - 1]) / ds[i - 1] + + (dxs[i] + 2 * dxs[i - 1]) / ds[i]); + + if(!isFinite(ms[i])) { + ms[i] = 0; + } + } + } + + // Now build a path from the slopes + + path = new Chartist.Svg.Path().move(xs[0], ys[0], false, valueData[0]); + + for(i = 0; i < n - 1; i++) { + path.curve( + // First control point + xs[i] + dxs[i] / 3, + ys[i] + ms[i] * dxs[i] / 3, + // Second control point + xs[i + 1] - dxs[i] / 3, + ys[i + 1] - ms[i + 1] * dxs[i] / 3, + // End point + xs[i + 1], + ys[i + 1], + + false, + valueData[i] + ); + } + + return path; + } + }; + }; + /** * 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. * From 36f7e7de84dc8b0bbea734a9f52e969573aafd72 Mon Sep 17 00:00:00 2001 From: James Watmuff Date: Tue, 29 Mar 2016 20:55:14 +1100 Subject: [PATCH 395/593] Refactor `splitIntoSegments` into core --- src/scripts/core.js | 67 +++++++++++++++++++++++++++++ src/scripts/interpolation.js | 82 +++--------------------------------- test/spec/spec-core.js | 63 ++++++++++++++++++++++++++- 3 files changed, 135 insertions(+), 77 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 7c3b4d3e..a493fd6d 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -995,4 +995,71 @@ var Chartist = { }; }; + + /** + * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates + * valueData property describing the segment. + * + * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any + * points with undefined values are discarded. + * + * **Options** + * The following options are used to determine how segments are formed + * ```javascript + * var options = { + * // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment. + * fillHoles: false, + * // If increasingX is true, the coordinates in all segments have strictly increasing x-values. + * increasingX: false + * }; + * ``` + * + * @memberof Chartist.Core + * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn] + * @param {Array} values List of associated point values in the form [v1, v2 .. vn] + * @param {Object} options Options set by user + * @return {Array} List of segments, each containing a pathCoordinates and valueData property. + */ + Chartist.splitIntoSegments = function(pathCoordinates, valueData, options) { + var defaultOptions = { + increasingX: false, + fillHoles: false + }; + + options = Chartist.extend({}, defaultOptions, options); + + var segments = []; + var hole = true; + + for(var i = 0; i < pathCoordinates.length; i += 2) { + // If this value is a "hole" we set the hole flag + if(valueData[i / 2].value === undefined) { + if(!options.fillHoles) { + hole = true; + } + } else { + if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) { + // X is not increasing, so we need to make sure we start a new segment + hole = true; + } + + + // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment + if(hole) { + segments.push({ + pathCoordinates: [], + valueData: [] + }); + // As we have a valid value now, we are not in a "hole" anymore + hole = false; + } + + // Add to the segment pathCoordinates and valueData + segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); + segments[segments.length - 1].valueData.push(valueData[i / 2]); + } + } + + return segments; + }; }(window, document, Chartist)); diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 362f8b9b..c7670287 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -162,43 +162,12 @@ var t = Math.min(1, Math.max(0, options.tension)), c = 1 - t; - // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates - // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards. - // This functionality is necessary to treat "holes" in the line charts - function splitIntoSegments(pathCoordinates, valueData) { - var segments = []; - var hole = true; - - for(var i = 0; i < pathCoordinates.length; i += 2) { - // If this value is a "hole" we set the hole flag - if(valueData[i / 2].value === undefined) { - if(!options.fillHoles) { - hole = true; - } - } else { - // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment - if(hole) { - segments.push({ - pathCoordinates: [], - valueData: [] - }); - // As we have a valid value now, we are not in a "hole" anymore - hole = false; - } - - // Add to the segment pathCoordinates and valueData - segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); - segments[segments.length - 1].valueData.push(valueData[i / 2]); - } - } - - return segments; - } - return function cardinal(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts - var segments = splitIntoSegments(pathCoordinates, valueData); + var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles + }); if(!segments.length) { // If there were no segments return 'Chartist.Interpolation.none' @@ -298,50 +267,13 @@ options = Chartist.extend({}, defaultOptions, options); - // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates - // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards. - // This functionality is necessary to treat "holes" in the line charts - function splitIntoSegments(pathCoordinates, valueData) { - var segments = []; - var hole = true; - - for(var i = 0; i < pathCoordinates.length; i += 2) { - // If this value is a "hole" we set the hole flag - if(valueData[i / 2].value === undefined) { - if(!options.fillHoles) { - hole = true; - } - } else if(i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) { - // Because we are doing monotone interpolation, curve fitting only makes sense for - // increasing x values. Therefore if two subsequent points have the same x value, or - // the x value is decreasing, then we create a hole at this point. (Which cannot be - // filled in even with the 'fillHoles' option) - - hole = true; - } else { - // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment - if(hole) { - segments.push({ - pathCoordinates: [], - valueData: [] - }); - // As we have a valid value now, we are not in a "hole" anymore - hole = false; - } - - // Add to the segment pathCoordinates and valueData - segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); - segments[segments.length - 1].valueData.push(valueData[i / 2]); - } - } - - return segments; - } - return function monotoneCubic(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts - var segments = splitIntoSegments(pathCoordinates, valueData); + var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles, + increasingX: true + }); if(!segments.length) { // If there were no segments return 'Chartist.Interpolation.none' diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index e28a3a1e..8f4712eb 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -396,6 +396,65 @@ describe('Chartist core', function() { }); }); - - + + describe('splitIntoSegments', function() { + + function makeValues(arr) { + return arr.map(function(x) { + return { value: x } + }); + } + + it('should return empty array for empty input', function() { + expect(Chartist.splitIntoSegments([],[])).toEqual([]); + }); + + it('should remove undefined values', function() { + var coords = [1,2,3,4,5,6,7,8,9,10,11,12]; + var values = makeValues([1,undefined,undefined,4,undefined,6]); + + expect(Chartist.splitIntoSegments(coords, values)).toEqual([{ + pathCoordinates: [1,2], + valueData: makeValues([1]) + }, { + pathCoordinates: [7, 8], + valueData: makeValues([4]) + }, { + pathCoordinates: [11, 12], + valueData: makeValues([6]) + }]); + }); + + it('should respect fillHoles option', function() { + var coords = [1,2,3,4,5,6,7,8,9,10,11,12]; + var values = makeValues([1,undefined,undefined,4,undefined,6]); + var options = { + fillHoles: true + }; + + expect(Chartist.splitIntoSegments(coords, values, options)).toEqual([{ + pathCoordinates: [1,2,7,8,11,12], + valueData: makeValues([1,4,6]) + }]); + }); + + it('should respect increasingX option', function() { + var coords = [1,2,3,4,5,6,5,6,7,8,1,2]; + var values = makeValues([1,2,3,4,5,6]); + var options = { + increasingX: true + }; + + expect(Chartist.splitIntoSegments(coords, values, options)).toEqual([{ + pathCoordinates: [1,2,3,4,5,6], + valueData: makeValues([1,2,3]) + }, { + pathCoordinates: [5,6,7,8], + valueData: makeValues([4,5]) + }, { + pathCoordinates: [1,2], + valueData: makeValues([6]) + }]); + }); + }); }); From 833beaeb859b51b4939cc05b8d8e874ff32aa555 Mon Sep 17 00:00:00 2001 From: James Watmuff Date: Tue, 29 Mar 2016 21:10:57 +1100 Subject: [PATCH 396/593] Add test for monotoneCubic interpolation --- test/spec/spec-line-chart.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index b4cf31fe..96964f1a 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -209,6 +209,40 @@ describe('Line chart tests', function () { }); }); + it('should render correctly with Interpolation.monotoneCubic and holes everywhere', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }, { + lineSmooth: Chartist.Interpolation.monotoneCubic() + }); + + chart.on('draw', function (context) { + if (context.type === 'line') { + expect(context.path.pathElements.map(function (pathElement) { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + // Monotone cubic should create Line path segment if only one connection + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + // Monotone cubic should create Curve path segment for 2 or more connections + {command: 'C', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} + ]); + done(); + } + }); + }); + it('should render correctly with Interpolation.simple and holes everywhere', function (done) { jasmine.getFixtures().set('
    '); From 3265b262927cf322abeb162f924db1c797bcb2a7 Mon Sep 17 00:00:00 2001 From: James Watmuff Date: Tue, 29 Mar 2016 21:12:29 +1100 Subject: [PATCH 397/593] Fix bug with monotoneCubic interpolation where associated value indexes were off by one --- src/scripts/interpolation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index c7670287..62a358df 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -359,7 +359,7 @@ ys[i + 1], false, - valueData[i] + valueData[i + 1] ); } From 1a6775868af1e4139a2d9f4f100ec5fc03d85b0b Mon Sep 17 00:00:00 2001 From: James Watmuff Date: Tue, 29 Mar 2016 21:13:55 +1100 Subject: [PATCH 398/593] Code style fix --- test/spec/spec-core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 8f4712eb..2d499d90 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -401,7 +401,7 @@ describe('Chartist core', function() { function makeValues(arr) { return arr.map(function(x) { - return { value: x } + return { value: x }; }); } From e8e61a728156f67657f6213e699eb92500a39f1c Mon Sep 17 00:00:00 2001 From: David Date: Wed, 13 Apr 2016 14:06:46 +1000 Subject: [PATCH 399/593] Corrected JSDoc of attr The "ns" parameter is optional and should be documented as such. --- src/scripts/svg.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index be20ade4..ed87a49c 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -55,7 +55,7 @@ * * @memberof Chartist.Svg * @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. - * @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. + * @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. * @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. */ function attr(attributes, ns) { From ef0429ac687b5c832f8fd44f7d84d6cf11fbe499 Mon Sep 17 00:00:00 2001 From: cheese83 Date: Wed, 13 Apr 2016 19:42:44 +0100 Subject: [PATCH 400/593] Improved the performance of Chartist.extend by making the following changes: - Use target[prop] as the target for the recursive call to extend, as it would be discarded otherwise. - Use for loop over arguments instead of slice+forEach. - Cache source[prop]. --- src/scripts/core.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index a493fd6d..cfeafedc 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -56,18 +56,20 @@ var Chartist = { * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source */ Chartist.extend = function (target) { + var i, source, sourceProp; target = target || {}; - var sources = Array.prototype.slice.call(arguments, 1); - sources.forEach(function(source) { + for (i = 1; i < arguments.length; i++) { + source = arguments[i]; for (var prop in source) { - if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) { - target[prop] = Chartist.extend({}, target[prop], source[prop]); + sourceProp = source[prop]; + if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { + target[prop] = Chartist.extend(target[prop], sourceProp); } else { - target[prop] = source[prop]; + target[prop] = sourceProp; } } - }); + }; return target; }; From 691153aac4599cac7b20af2cf65ce28232115d03 Mon Sep 17 00:00:00 2001 From: Gerhard Preuss Date: Thu, 28 Apr 2016 11:48:10 +0200 Subject: [PATCH 401/593] add doclets.io config --- .doclets.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .doclets.yml diff --git a/.doclets.yml b/.doclets.yml new file mode 100644 index 00000000..532a1476 --- /dev/null +++ b/.doclets.yml @@ -0,0 +1 @@ +dir: src/scripts From 719192297cbd65303d2c6465f99642b85dada5cb Mon Sep 17 00:00:00 2001 From: Paul Curry Date: Fri, 29 Apr 2016 10:44:05 +0100 Subject: [PATCH 402/593] Remove "self" reference, which Prototype.js seems to dislike --- dist/chartist.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/dist/chartist.js b/dist/chartist.js index 8f08a006..f00933ab 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -1993,13 +1993,10 @@ var Chartist = { * @return {Chartist.Svg} The wrapper of the current element */ function addClass(names) { - this._node.setAttribute('class', - this.classes(this._node) - .concat(names.trim().split(/\s+/)) - .filter(function(elem, pos, self) { - return self.indexOf(elem) === pos; - }).join(' ') - ); + var arr = this.classes(this._node).concat(names.trim().split(/\s+/)); + this._node.setAttribute('class', arr.filter(function(elem, pos) { + return arr.indexOf(elem) === pos; + }).join(' ')); return this; } From 8de8679ed6d565410d3dd07dcf2af94efa0b365c Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 08:24:52 +0200 Subject: [PATCH 403/593] Fixed linting issue --- src/scripts/core.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index a493fd6d..9855a853 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -730,7 +730,7 @@ var Chartist = { // step must not be less than EPSILON to create values that can be represented as floating number. var EPSILON = 2.221E-16; bounds.step = Math.max(bounds.step, EPSILON); - + // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; @@ -745,9 +745,11 @@ var Chartist = { bounds.range = bounds.max - bounds.min; var values = []; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { - var value = Chartist.roundWithPrecision(i); - value != values[values.length - 1] && values.push(i); + for (i = bounds.min; i <= bounds.max; i += bounds.step) { + var value = Chartist.roundWithPrecision(i); + if (value !== values[values.length - 1]) { + values.push(i); + } } bounds.values = values; return bounds; From 7365c04edee23232b014de7f03c21d7f2ab47e84 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 08:55:14 +0200 Subject: [PATCH 404/593] Updated development pipeline dependencies --- package.json | 48 ++++++++++++++++++++++++------------------------ tasks/jasmine.js | 4 ++-- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 6844ca79..3d46af6c 100644 --- a/package.json +++ b/package.json @@ -40,38 +40,38 @@ ], "dependencies": {}, "devDependencies": { - "assemble": "~0.4.42", "assemble-dox": "0.0.2", - "grunt": "^0.4.5", - "grunt-concurrent": "^1.0.0", - "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-concat": "^0.5.0", - "grunt-contrib-connect": "~0.9.0", - "grunt-contrib-copy": "^0.7.0", - "grunt-contrib-cssmin": "^0.12.1", - "grunt-contrib-htmlmin": "~0.4.0", + "grunt": "^1.0.1", + "grunt-concurrent": "^2.3.0", + "grunt-contrib-clean": "^1.0.0", + "grunt-contrib-concat": "^1.0.1", + "grunt-contrib-connect": "^1.0.2", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-cssmin": "^1.0.1", + "grunt-contrib-htmlmin": "^1.4.0", "grunt-contrib-imagemin": "^1.0.0", - "grunt-contrib-jasmine": "~0.8.2", - "grunt-contrib-jshint": "~0.11.0", - "grunt-contrib-uglify": "^0.7.0", - "grunt-contrib-watch": "^0.6.1", - "grunt-critical": "0.1.1", + "grunt-contrib-jasmine": "^1.0.3", + "grunt-contrib-jshint": "^1.0.0", + "grunt-contrib-uglify": "^1.0.1", + "grunt-contrib-watch": "^1.0.0", + "grunt-critical": "^0.2.1", "grunt-newer": "^1.1.0", "grunt-sass": "^1.1.0", - "grunt-svgmin": "~2.0.0", + "grunt-svgmin": "^3.2.0", "grunt-template": "^0.2.3", - "grunt-umd": "~2.3.1", - "grunt-usemin": "~3.0.0", - "handlebars-helpers": "~0.5.8", - "jasmine-jquery": "~2.0.6", - "jshint-stylish": "~1.0.0", - "load-grunt-config": "^0.16.0", - "lodash": "~2.4.1", - "seed-random": "~2.2.0", + "grunt-umd": "^2.3.1", + "grunt-usemin": "^3.1.1", + "handlebars-helpers": "^0.6.1", + "jasmine-jquery": "^2.1.1", + "jquery": "^3.0.0", + "jshint-stylish": "^2.2.0", + "load-grunt-config": "^0.19.2", + "lodash": "^4.13.1", + "seed-random": "^2.2.0", "time-grunt": "^1.0.0" }, "engines": { - "node": ">=0.8.0" + "node": ">=5.5.0" }, "scripts": { "test": "grunt test" diff --git a/tasks/jasmine.js b/tasks/jasmine.js index 4fa2feed..5e3fbc3a 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -31,8 +31,8 @@ module.exports = function (grunt) { options: { specs: '<%= pkg.config.test %>/spec/**/spec-*.js', helpers: '<%= pkg.config.test %>/spec/**/helper-*.js', - vendor: [ - 'node_modules/jasmine-jquery/vendor/jquery/jquery.js', + vendor: [ + 'node_modules/jquery/dist/jquery.js', 'node_modules/jasmine-jquery/lib/jasmine-jquery.js' ], styles: [ From 4453299f437c58e8ea95c3c2b5458f77ad3847d9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 08:55:25 +0200 Subject: [PATCH 405/593] Fixed linting issue --- test/spec/spec-pie-chart.js | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index f83d900c..6108d78f 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -39,8 +39,9 @@ describe('Pie chart tests', function() { var num = '\\d+(\\.\\d*)?'; var data, options; - + beforeEach(function() { + var sum = function(a, b) { return a + b; }; data = { series: [5, 3, 4] }; @@ -52,9 +53,8 @@ describe('Pie chart tests', function() { return Math.round(value / data.series.reduce(sum) * 100) + '%'; } }; - var sum = function(a, b) { return a + b; }; }); - + function onCreated(callback) { jasmine.getFixtures().set('
    '); var chart = new Chartist.Pie('.ct-chart', data, options); @@ -101,7 +101,7 @@ describe('Pie chart tests', function() { done(); }); }); - + it('should overlap slices', function(done) { data = { series: [1, 1] @@ -137,7 +137,7 @@ describe('Pie chart tests', function() { done(); }); }); - + it('should draw complete circle with startAngle', function(done) { data.series = [100]; options.startAngle = 90; @@ -147,7 +147,7 @@ describe('Pie chart tests', function() { done(); }); }); - + it('should draw complete circle if values are 0', function(done) { data = { series: [0, 1, 0] @@ -172,7 +172,7 @@ describe('Pie chart tests', function() { width: 100, height: 100, chartPadding: 0, - }; + }; }); function onCreated(callback) { @@ -182,7 +182,7 @@ describe('Pie chart tests', function() { } it('Pie should render correctly with very small slices', function(done) { - onCreated(function() { + onCreated(function() { var slice1 = $('.ct-slice-pie').eq(0); var slice2 = $('.ct-slice-pie').eq(1); @@ -191,10 +191,10 @@ describe('Pie chart tests', function() { done(); }); }); - + it('Pie should render correctly with very small slices on startAngle', function(done) { options.startAngle = 90; - onCreated(function() { + onCreated(function() { var slice1 = $('.ct-slice-pie').eq(0); var slice2 = $('.ct-slice-pie').eq(1); @@ -206,7 +206,7 @@ describe('Pie chart tests', function() { it('Donut should render correctly with very small slices', function(done) { options.donut = true; - onCreated(function() { + onCreated(function() { var slice1 = $('.ct-slice-donut').eq(0); var slice2 = $('.ct-slice-donut').eq(1); @@ -217,7 +217,7 @@ describe('Pie chart tests', function() { }); }); - + describe('Pie with some empty values configured to be ignored', function() { var data, options; @@ -239,11 +239,11 @@ describe('Pie chart tests', function() { } it('Pie should not render empty slices', function(done) { - onCreated(function() { + onCreated(function() { var slices = $('.ct-slice-pie'); - + expect(slices.length).toBe(3); - + expect(slices.eq(2).attr('ct:value')).toBe('1'); expect(slices.eq(1).attr('ct:value')).toBe('2'); expect(slices.eq(0).attr('ct:value')).toBe('4'); @@ -251,7 +251,7 @@ describe('Pie chart tests', function() { }); }); }); - + describe('Pie with some empty values configured not to be ignored', function() { var data, options; @@ -263,7 +263,7 @@ describe('Pie chart tests', function() { width: 100, height: 100, ignoreEmptyValues: false - }; + }; }); function onCreated(callback) { @@ -273,11 +273,11 @@ describe('Pie chart tests', function() { } it('Pie should render empty slices', function(done) { - onCreated(function() { + onCreated(function() { var slices = $('.ct-slice-pie'); - + expect(slices.length).toBe(4); - + expect(slices.eq(3).attr('ct:value')).toBe('1'); expect(slices.eq(2).attr('ct:value')).toBe('2'); expect(slices.eq(1).attr('ct:value')).toBe('0'); From eda1288230d2d213c84d7fbdc466f11e84d29293 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 09:03:19 +0200 Subject: [PATCH 406/593] Updated chartist tooltip plugin and example styles --- bower.json | 2 +- site/styles/_example-charts.scss | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/bower.json b/bower.json index d9e517ac..197bb4e7 100755 --- a/bower.json +++ b/bower.json @@ -14,7 +14,7 @@ "chartist-plugin-pointlabels": "~0.0.4", "chartist-plugin-sketchy": "~0.0.2", "chartist-plugin-accessibility": "~0.0.2", - "chartist-plugin-tooltip": "~0.0.8", + "chartist-plugin-tooltip": "~0.0.12", "chartist-plugin-axistitle": "~0.0.1", "chartist-plugin-threshold": "~0.0.1", "chartist-plugin-fill-donut": "~0.0.1", diff --git a/site/styles/_example-charts.scss b/site/styles/_example-charts.scss index f65cd26c..71d3c08f 100755 --- a/site/styles/_example-charts.scss +++ b/site/styles/_example-charts.scss @@ -108,3 +108,37 @@ stroke: red; } } +#example-plugin-tooltip { + .chart { + position: relative; + } + + .chartist-tooltip { + position: absolute; + display: block; + min-width: 5em; + padding: .5em; + background: #F4C63D; + color: #453D3F; + font-family: Oxygen,Helvetica,Arial,sans-serif; + font-weight: 700; + text-align: center; + pointer-events: none; + z-index: 1; + -webkit-transition: opacity .2s linear; + -moz-transition: opacity .2s linear; + -o-transition: opacity .2s linear; + transition: opacity .2s linear; } + .chartist-tooltip:before { + content: ""; + position: absolute; + top: 100%; + left: 50%; + width: 0; + height: 0; + margin-left: -15px; + border: 15px solid transparent; + border-top-color: #F4C63D; } + .chartist-tooltip.tooltip-show { + opacity: 1; } +} From 4d30c3777e5f8ab776d87625d0b92be297041069 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 09:06:18 +0200 Subject: [PATCH 407/593] Removed sketchy plugin --- bower.json | 1 - site/data/pages/plugins.yml | 26 ----------------- site/examples/example-plugin-sketchy.js | 37 ------------------------- site/layouts/default.hbs | 1 - 4 files changed, 65 deletions(-) delete mode 100644 site/examples/example-plugin-sketchy.js diff --git a/bower.json b/bower.json index 197bb4e7..be74fc1a 100755 --- a/bower.json +++ b/bower.json @@ -12,7 +12,6 @@ "codemirror": "~4.12.0", "base64": "~0.3.0", "chartist-plugin-pointlabels": "~0.0.4", - "chartist-plugin-sketchy": "~0.0.2", "chartist-plugin-accessibility": "~0.0.2", "chartist-plugin-tooltip": "~0.0.12", "chartist-plugin-axistitle": "~0.0.1", diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index 1bdcfce4..a25c3a21 100755 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -153,32 +153,6 @@ sections: - 'Link:' - 'chartist-plugin-pointlabels' - - type: sub-section - data: - title: Sketchy Plugin - level: 4 - items: - - type: text - data: - text: > - The sketchy plugin makes your charts look like they have been drawn by hand. This plugin makes use - of SVG filters and works on IE10+, Safari 7+ and Android 4.4+. Also note that SVG filters are not - very performant and they will eat your users mobile battery quickly for sure. - - type: live-example - data: - id: example-plugin-sketchy - classes: ct-golden-section - intro: > - Create beautiful hand drawn charts using the Chartist Sketchy plugin. - - type: table - data: - rows: - - - - 'Author:' - - Gion Kunz - - - - 'Link:' - - 'chartist-plugin-sketchy' - type: sub-section data: title: Axis Title Plugin diff --git a/site/examples/example-plugin-sketchy.js b/site/examples/example-plugin-sketchy.js deleted file mode 100644 index 35609901..00000000 --- a/site/examples/example-plugin-sketchy.js +++ /dev/null @@ -1,37 +0,0 @@ -new Chartist.Bar('.ct-chart', { - labels: ['Q1', 'Q2', 'Q3', 'Q4'], - series: [ - [800000, 1200000, 1400000, 1300000], - [200000, 400000, 500000, 300000], - [100000, 200000, 400000, 600000] - ] -}, { - plugins: [ - Chartist.plugins.ctSketchy({ - overrides: { - grid: { - baseFrequency: 0.2, - scale: 5, - numOctaves: 1 - }, - bar: { - baseFrequency: 0.02, - scale: 10 - }, - label: false - } - }) - ], - stackBars: true, - axisY: { - labelInterpolationFnc: function(value) { - return (value / 1000) + 'k'; - } - } -}).on('draw', function(data) { - if(data.type === 'bar') { - data.element.attr({ - style: 'stroke-width: 30px' - }); - } -}); diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index f919a6ba..5bd28a59 100755 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -70,7 +70,6 @@ - From a5f41ce1b1743dfd4ebcbb3270a9efefd001438d Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 09:21:15 +0200 Subject: [PATCH 408/593] Switched to monotoneCubic interpolation for default line chart smoothing --- src/scripts/charts/line.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index b1d3e145..30f60683 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -189,7 +189,7 @@ }; var smoothing = typeof seriesOptions.lineSmooth === 'function' ? - seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()); + seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.monotoneCubic() : Chartist.Interpolation.none()); // Interpolating path where pathData will be used to annotate each path element so we can trace back the original // index, value and meta data var path = smoothing(pathCoordinates, pathData); From c034ae3eb066b2ee351d76f8bb31a48558ab05ad Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 09:25:25 +0200 Subject: [PATCH 409/593] Fixed WTFPL License issue --- LICENSE-WTFPL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE-WTFPL b/LICENSE-WTFPL index 792ed5b9..5c93f456 100644 --- a/LICENSE-WTFPL +++ b/LICENSE-WTFPL @@ -1,7 +1,7 @@ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 - Copyright (c) 2013 Gion Kunz + Copyright (C) 2004 Sam Hocevar Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long From beabb2793ab67da84cadc0b91d5fd509f2cdfc55 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 09:36:27 +0200 Subject: [PATCH 410/593] Dist and version bump --- CHANGELOG.md | 12 ++ dist/chartist.css | 18 ++- dist/chartist.css.map | 7 +- dist/chartist.js | 264 ++++++++++++++++++++++++++++++++------- dist/chartist.min.js | 6 +- dist/chartist.min.js.map | 2 +- package.json | 2 +- 7 files changed, 256 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 181f1461..df1e0a07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +v0.9.8 - 22 Jun 2016 +-------------------- +- Added monotone cubic interpolation which is now the default interpolation for line charts +- Update zoom plugin to 0.2.1 +- Bugfix: Prevent infinite loop in getBounds if bounds.valueRange is very small, fixes #643 +- Bugfix: Correct update events during media changes +- Bugfix: prevent negative value for foreignObject width attribute +- Fixed example line chart in getting started documentation +- Updated development pipeline dependencies +- Updated chartist tooltip plugin and example styles +- Fixed WTFPL License issue + v0.9.7 - 23 Feb 2016 -------------------- - Fixed bug with label and grid rendering on axis, fixes #621 diff --git a/dist/chartist.css b/dist/chartist.css index 8f06df02..936025de 100644 --- a/dist/chartist.css +++ b/dist/chartist.css @@ -4,7 +4,8 @@ font-size: 0.75rem; line-height: 1; } -.ct-chart-line .ct-label, .ct-chart-bar .ct-label { +.ct-chart-line .ct-label, +.ct-chart-bar .ct-label { display: block; display: -webkit-box; display: -moz-box; @@ -159,76 +160,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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { fill: #a748ca; } diff --git a/dist/chartist.css.map b/dist/chartist.css.map index d1353ddc..6bd28332 100644 --- a/dist/chartist.css.map +++ b/dist/chartist.css.map @@ -2,10 +2,9 @@ "version": 3, "file": "chartist.css", "sources": [ - "../../chartist.scss", - "../../settings/_chartist-settings.scss" + "../../src/styles/chartist.scss", + "../../src/styles/settings/_chartist-settings.scss" ], - "sourcesContent": [], - "mappings": "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", + "mappings": "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", "names": [] } \ No newline at end of file diff --git a/dist/chartist.js b/dist/chartist.js index 8f08a006..c7154502 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.7 +/* Chartist.js 0.9.8 * Copyright © 2016 Gion Kunz * Free to use under either the WTFPL license or the MIT license. * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL @@ -26,7 +26,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.7' + version: '0.9.8' }; (function (window, document, Chartist) { @@ -749,6 +749,10 @@ var Chartist = { } } + // step must not be less than EPSILON to create values that can be represented as floating number. + var EPSILON = 2.221E-16; + bounds.step = Math.max(bounds.step, EPSILON); + // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; @@ -762,11 +766,14 @@ var Chartist = { bounds.max = newMax; bounds.range = bounds.max - bounds.min; - bounds.values = []; + var values = []; for (i = bounds.min; i <= bounds.max; i += bounds.step) { - bounds.values.push(Chartist.roundWithPrecision(i)); + var value = Chartist.roundWithPrecision(i); + if (value !== values[values.length - 1]) { + values.push(i); + } } - + bounds.values = values; return bounds; }; @@ -904,7 +911,7 @@ var Chartist = { positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; positionalData[axis.units.len] = length; - positionalData[axis.counterUnits.len] = axisOffset - 10; + positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10); if(useForeignObject) { // We need to set width and height explicitly to px as span will not expand with width and height being @@ -964,7 +971,7 @@ var Chartist = { mediaQueryListeners = [], i; - function updateCurrentOptions(preventChangedEvent) { + function updateCurrentOptions(mediaEvent) { var previousOptions = currentOptions; currentOptions = Chartist.extend({}, baseOptions); @@ -977,7 +984,7 @@ var Chartist = { } } - if(eventEmitter && !preventChangedEvent) { + if(eventEmitter && mediaEvent) { eventEmitter.emit('optionsChanged', { previousOptions: previousOptions, currentOptions: currentOptions @@ -1001,8 +1008,8 @@ var Chartist = { mediaQueryListeners.push(mql); } } - // Execute initially so we get the correct options - updateCurrentOptions(true); + // Execute initially without an event argument so we get the correct options + updateCurrentOptions(); return { removeMediaQueryListeners: removeMediaQueryListeners, @@ -1012,6 +1019,73 @@ var Chartist = { }; }; + + /** + * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates + * valueData property describing the segment. + * + * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any + * points with undefined values are discarded. + * + * **Options** + * The following options are used to determine how segments are formed + * ```javascript + * var options = { + * // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment. + * fillHoles: false, + * // If increasingX is true, the coordinates in all segments have strictly increasing x-values. + * increasingX: false + * }; + * ``` + * + * @memberof Chartist.Core + * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn] + * @param {Array} values List of associated point values in the form [v1, v2 .. vn] + * @param {Object} options Options set by user + * @return {Array} List of segments, each containing a pathCoordinates and valueData property. + */ + Chartist.splitIntoSegments = function(pathCoordinates, valueData, options) { + var defaultOptions = { + increasingX: false, + fillHoles: false + }; + + options = Chartist.extend({}, defaultOptions, options); + + var segments = []; + var hole = true; + + for(var i = 0; i < pathCoordinates.length; i += 2) { + // If this value is a "hole" we set the hole flag + if(valueData[i / 2].value === undefined) { + if(!options.fillHoles) { + hole = true; + } + } else { + if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) { + // X is not increasing, so we need to make sure we start a new segment + hole = true; + } + + + // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment + if(hole) { + segments.push({ + pathCoordinates: [], + valueData: [] + }); + // As we have a valid value now, we are not in a "hole" anymore + hole = false; + } + + // Add to the segment pathCoordinates and valueData + segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); + segments[segments.length - 1].valueData.push(valueData[i / 2]); + } + } + + return segments; + }; }(window, document, Chartist)); ;/** * Chartist path interpolation functions. @@ -1177,43 +1251,12 @@ var Chartist = { var t = Math.min(1, Math.max(0, options.tension)), c = 1 - t; - // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates - // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards. - // This functionality is necessary to treat "holes" in the line charts - function splitIntoSegments(pathCoordinates, valueData) { - var segments = []; - var hole = true; - - for(var i = 0; i < pathCoordinates.length; i += 2) { - // If this value is a "hole" we set the hole flag - if(valueData[i / 2].value === undefined) { - if(!options.fillHoles) { - hole = true; - } - } else { - // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment - if(hole) { - segments.push({ - pathCoordinates: [], - valueData: [] - }); - // As we have a valid value now, we are not in a "hole" anymore - hole = false; - } - - // Add to the segment pathCoordinates and valueData - segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); - segments[segments.length - 1].valueData.push(valueData[i / 2]); - } - } - - return segments; - } - return function cardinal(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts - var segments = splitIntoSegments(pathCoordinates, valueData); + var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles + }); if(!segments.length) { // If there were no segments return 'Chartist.Interpolation.none' @@ -1283,6 +1326,137 @@ var Chartist = { }; }; + /** + * 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. + * + * 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`. + * + * 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. + * + * All smoothing functions within Chartist are factory functions that accept an options parameter. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.monotoneCubic({ + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the monotoneCubic factory function. + * @return {Function} + */ + Chartist.Interpolation.monotoneCubic = function(options) { + var defaultOptions = { + fillHoles: false + }; + + options = Chartist.extend({}, defaultOptions, options); + + return function monotoneCubic(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles, + increasingX: true + }); + + if(!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return Chartist.Interpolation.none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; + // For each segment we will recurse the monotoneCubic fn function + segments.forEach(function(segment) { + paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return Chartist.Svg.Path.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; + + // If less than three points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return Chartist.Interpolation.none()(pathCoordinates, valueData); + } + + var xs = [], + ys = [], + i, + n = pathCoordinates.length / 2, + ms = [], + ds = [], dys = [], dxs = [], + path; + + // Populate x and y coordinates into separate arrays, for readability + + for(i = 0; i < n; i++) { + xs[i] = pathCoordinates[i * 2]; + ys[i] = pathCoordinates[i * 2 + 1]; + } + + // Calculate deltas and derivative + + for(i = 0; i < n - 1; i++) { + dys[i] = ys[i + 1] - ys[i]; + dxs[i] = xs[i + 1] - xs[i]; + ds[i] = dys[i] / dxs[i]; + } + + // Determine desired slope (m) at each point using Fritsch-Carlson method + // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation + + ms[0] = ds[0]; + ms[n - 1] = ds[n - 2]; + + for(i = 1; i < n - 1; i++) { + if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) { + ms[i] = 0; + } else { + ms[i] = 3 * (dxs[i - 1] + dxs[i]) / ( + (2 * dxs[i] + dxs[i - 1]) / ds[i - 1] + + (dxs[i] + 2 * dxs[i - 1]) / ds[i]); + + if(!isFinite(ms[i])) { + ms[i] = 0; + } + } + } + + // Now build a path from the slopes + + path = new Chartist.Svg.Path().move(xs[0], ys[0], false, valueData[0]); + + for(i = 0; i < n - 1; i++) { + path.curve( + // First control point + xs[i] + dxs[i] / 3, + ys[i] + ms[i] * dxs[i] / 3, + // Second control point + xs[i + 1] - dxs[i] / 3, + ys[i + 1] - ms[i + 1] * dxs[i] / 3, + // End point + xs[i + 1], + ys[i + 1], + + false, + valueData[i + 1] + ); + } + + return path; + } + }; + }; + /** * 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. * @@ -3153,7 +3327,7 @@ var Chartist = { }; var smoothing = typeof seriesOptions.lineSmooth === 'function' ? - seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none()); + seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.monotoneCubic() : Chartist.Interpolation.none()); // Interpolating path where pathData will be used to annotate each path element so we can trace back the original // index, value and meta data var path = smoothing(pathCoordinates, pathData); diff --git a/dist/chartist.min.js b/dist/chartist.min.js index fc39f873..ca5e4ef2 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,10 +1,10 @@ -/* Chartist.js 0.9.7 +/* Chartist.js 0.9.8 * Copyright © 2016 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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.7"};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){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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){if(a=a||{series:[],labels:[]},a.series=a.series||[],a.labels=a.labels||[],a.series.length>0&&0===a.labels.length){var b,d=c.getDataArray(a);b=d.every(function(a){return a instanceof Array})?Math.max.apply(null,d.map(function(a){return a.length})):d.length,a.labels=c.times(b).map(function(){return""})}return 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.isNum=function(a){return!isNaN(a)&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return isNaN(+a)?void 0:+a},c.getMultiValue=function(a,b){return c.isNum(a)?+a:a?a[b||"y"]||0:0},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){var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=c.orderOfMagnitude(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=c.projectLength(a,j.step,j),l=d>k,m=e?c.rho(j.range):0;if(e&&c.projectLength(a,1,j)>=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}for(g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;for(j.min=g,j.max=h,j.range=j.max-j.min,j.values=[],f=j.min;f<=j.max;f+=j.step)j.values.push(c.roundWithPrecision(f));return j},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.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]=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;i1){var i=[];return h.forEach(function(a){i.push(g(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(a=h[0].pathCoordinates,d=h[0].valueData,a.length<=4)return c.Interpolation.none()(a,d);for(var j,k=(new c.Svg.Path).move(a[0],a[1],!1,d[0]),l=0,m=a.length;m-2*!j>l;l+=2){var n=[{x:+a[l-2],y:+a[l-1]},{x:+a[l],y:+a[l+1]},{x:+a[l+2],y:+a[l+3]},{x:+a[l+4],y:+a[l+5]}];j?l?m-4===l?n[3]={x:+a[0],y:+a[1]}:m-2===l&&(n[2]={x:+a[0],y:+a[1]},n[3]={x:+a[2],y:+a[3]}):n[0]={x:+a[m-2],y:+a[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+a[l],y:+a[l+1]}),k.curve(e*(-n[0].x+6*n[1].x+n[2].x)/6+f*n[2].x,e*(-n[0].y+6*n[1].y+n[2].y)/6+f*n[2].y,e*(n[1].x+6*n[2].x-n[3].x)/6+f*n[2].x,e*(n[1].y+6*n[2].y-n[3].y)/6+f*n[2].y,n[2].x,n[2].y,!1,d[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.step=function(a){var b={postpone:!0,fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e,f,g,h=new c.Svg.Path,i=0;i1}).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[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,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",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){this.data=c.normalizeData(this.data);var b,d={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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!==d.normalized.length){var i=c.serialMap(d.normalized,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})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":b.name,"ct:meta":c.serialize(b.meta)}),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNum).join(","),"ct:meta":c.getMetaData(b,k)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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){this.data=c.normalizeData(this.data);var b,e,f,h,i,j=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p=359.99&&(r=s+359.99);var t=c.polarToCartesian(n.x,n.y,f,s),u=c.polarToCartesian(n.x,n.y,f,r),v=new c.Svg.Path(!a.donut).move(u.x,u.y).arc(f,f,0,r-k>180,0,t.x,t.y);a.donut||v.line(n.x,n.y);var w=j[p].elem("path",{d:v.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(w.attr({"ct:value":l[p],"ct:meta":c.serialize(q.meta)}),a.donut&&w.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:w,path:v.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var x=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),y=a.labelInterpolationFnc(this.data.labels&&!c.isFalseyButZero(this.data.labels[p])?this.data.labels[p]:l[p],p);if(y||0===y){var z=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":d(n,x,a.labelDirection)},a.classNames.label).text(""+y);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:z,text:""+y,x:x.x,y:x.y})}}k=r}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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.8"};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){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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){if(a=a||{series:[],labels:[]},a.series=a.series||[],a.labels=a.labels||[],a.series.length>0&&0===a.labels.length){var b,d=c.getDataArray(a);b=d.every(function(a){return a instanceof Array})?Math.max.apply(null,d.map(function(a){return a.length})):d.length,a.labels=c.times(b).map(function(){return""})}return 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.isNum=function(a){return!isNaN(a)&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return isNaN(+a)?void 0:+a},c.getMultiValue=function(a,b){return c.isNum(a)?+a:a?a[b||"y"]||0:0},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){var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=c.orderOfMagnitude(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=c.projectLength(a,j.step,j),l=k=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var n=2.221e-16;for(j.step=Math.max(j.step,n),g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;j.min=g,j.max=h,j.range=j.max-j.min;var o=[];for(f=j.min;f<=j.max;f+=j.step){var p=c.roundWithPrecision(f);p!==o[o.length-1]&&o.push(f)}return j.values=o,j},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.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[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,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",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){this.data=c.normalizeData(this.data);var b,d={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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!==d.normalized.length){var i=c.serialMap(d.normalized,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})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":b.name,"ct:meta":c.serialize(b.meta)}),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNum).join(","),"ct:meta":c.getMetaData(b,k)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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){this.data=c.normalizeData(this.data);var b,e,f,h,i,j=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p=359.99&&(r=s+359.99);var t=c.polarToCartesian(n.x,n.y,f,s),u=c.polarToCartesian(n.x,n.y,f,r),v=new c.Svg.Path((!a.donut)).move(u.x,u.y).arc(f,f,0,r-k>180,0,t.x,t.y);a.donut||v.line(n.x,n.y);var w=j[p].elem("path",{d:v.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(w.attr({"ct:value":l[p],"ct:meta":c.serialize(q.meta)}),a.donut&&w.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:w,path:v.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var x=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),y=a.labelInterpolationFnc(this.data.labels&&!c.isFalseyButZero(this.data.labels[p])?this.data.labels[p]:l[p],p);if(y||0===y){var z=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":d(n,x,a.labelDirection)},a.classNames.label).text(""+y);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:z,text:""+y,x:x.x,y:x.y})}}k=r}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}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index 54f7741d..6d39d513 100644 --- a/dist/chartist.min.js.map +++ b/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","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","series","labels","labelCount","normalized","getDataArray","every","reverseData","reverse","i","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","push","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","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","preventChangedEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","Interpolation","none","defaultOptions","fillHoles","pathCoordinates","valueData","path","Path","hole","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","splitIntoSegments","segments","tension","t","c","paths","segment","z","iLen","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","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","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([], 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.9.7\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.9.7'\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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) {\n // Ensure data is present otherwise enforce\n data = data || {series: [], labels: []};\n data.series = data.series || [];\n data.labels = data.labels || [];\n\n // Check if we should generate some labels based on existing series data\n if (data.series.length > 0 && data.labels.length === 0) {\n var normalized = Chartist.getDataArray(data),\n labelCount;\n\n // If all elements of the normalized data array are arrays we're dealing with\n // data from Bar or Line charts and we need to find the largest series if they are un-even\n if (normalized.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, normalized.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 = normalized.length;\n }\n\n // Setting labels to an array with emptry strings using our labelCount estimated above\n data.labels = Chartist.times(labelCount).map(function() {\n return '';\n });\n }\n return data;\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax -= bounds.step;\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n bounds.values = [];\n for (i = bounds.min; i <= bounds.max; i += bounds.step) {\n bounds.values.push(Chartist.roundWithPrecision(i));\n }\n\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 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] = 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(preventChangedEvent) {\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 && !preventChangedEvent) {\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 so we get the correct options\n updateCurrentOptions(true);\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\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(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 // This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates\n // and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.\n // This functionality is necessary to treat \"holes\" in the line charts\n function splitIntoSegments(pathCoordinates, valueData) {\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(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\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\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 = splitIntoSegments(pathCoordinates, valueData);\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 * 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 // 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.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 * 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 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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.cardinal() : 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.isNum).join(','),\n 'ct:meta': 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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[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 // 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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),\n 'ct:meta': Chartist.getMetaData(series, valueIndex)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 this.data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;\n\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (i === 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[i].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': dataArray[i],\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);\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: i,\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 }\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","exports","module","this","Chartist","version","window","document","namespaces","svg","xmlns","xhtml","xlink","ct","noop","n","alphaNumerate","String","fromCharCode","extend","target","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","series","labels","labelCount","normalized","getDataArray","every","reverseData","reverse","i","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","EPSILON","values","push","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","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","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","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([], 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.9.8\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.9.8'\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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) {\n // Ensure data is present otherwise enforce\n data = data || {series: [], labels: []};\n data.series = data.series || [];\n data.labels = data.labels || [];\n\n // Check if we should generate some labels based on existing series data\n if (data.series.length > 0 && data.labels.length === 0) {\n var normalized = Chartist.getDataArray(data),\n labelCount;\n\n // If all elements of the normalized data array are arrays we're dealing with\n // data from Bar or Line charts and we need to find the largest series if they are un-even\n if (normalized.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, normalized.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 = normalized.length;\n }\n\n // Setting labels to an array with emptry strings using our labelCount estimated above\n data.labels = Chartist.times(labelCount).map(function() {\n return '';\n });\n }\n return data;\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // step must not be less than EPSILON to create values that can be represented as floating number.\n var EPSILON = 2.221E-16;\n bounds.step = Math.max(bounds.step, EPSILON);\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n 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 += bounds.step) {\n var value = Chartist.roundWithPrecision(i);\n if (value !== values[values.length - 1]) {\n values.push(i);\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 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(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(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 // 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.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 * 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 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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.isNum).join(','),\n 'ct:meta': 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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[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 // 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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),\n 'ct:meta': Chartist.getMetaData(series, valueIndex)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 this.data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;\n\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (i === 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[i].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': dataArray[i],\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);\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: i,\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 }\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/package.json b/package.json index 3d46af6c..19e2a9ff 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.7", + "version": "0.9.8", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 0cb7b76fee6d96b81cf2c0b8cd4b979387b99649 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Wed, 22 Jun 2016 09:45:26 +0200 Subject: [PATCH 411/593] Updated travis node version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a80b6e03..405a6c49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - '0.10' + - '5.5.0' before_script: - 'npm install -g bower grunt-cli' - 'bower install' From 099ab6aa03554cf9d448d3b8fab4a099f9a21d18 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Thu, 23 Jun 2016 09:53:02 +0200 Subject: [PATCH 412/593] Fix infinite loop in getBounds with a more robust increment. This is related to bfdc8f2 which introduced a EPSILON as the smallest increment but fails for bigger numbers. --- src/scripts/core.js | 18 ++++++++++++------ test/spec/spec-core.js | 9 +++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 9855a853..5216de3e 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -727,25 +727,31 @@ var Chartist = { } } - // step must not be less than EPSILON to create values that can be represented as floating number. var EPSILON = 2.221E-16; bounds.step = Math.max(bounds.step, EPSILON); + function safeIncrement(value, increment) { + // If increment is too small use *= (1+EPSILON) as a simple nextafter + if (value === (value += increment)) { + value *= (1 + (increment > 0 ? EPSILON : -EPSILON)); + } + return value; + } // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; - while(newMin + bounds.step <= bounds.low) { - newMin += bounds.step; + while (newMin + bounds.step <= bounds.low) { + newMin = safeIncrement(newMin, bounds.step); } - while(newMax - bounds.step >= bounds.high) { - newMax -= bounds.step; + while (newMax - bounds.step >= bounds.high) { + newMax = safeIncrement(newMax, -bounds.step); } bounds.min = newMin; bounds.max = newMax; bounds.range = bounds.max - bounds.min; var values = []; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { + for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { var value = Chartist.roundWithPrecision(i); if (value !== values[values.length - 1]) { values.push(i); diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 2d499d90..e75c0e61 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -395,6 +395,15 @@ describe('Chartist core', function() { expect(bounds.values).toEqual([1]); }); + it('should return single step if range is less than smallest increment', function() { + var bounds = Chartist.getBounds(613.234375, { high: 1000.0000000000001, low: 999.9999999999997 }, 50, false); + expect(bounds.min).toBe(999.9999999999999); + expect(bounds.max).toBe(1000); + expect(bounds.low).toBe(999.9999999999997); + expect(bounds.high).toBe(1000.0000000000001); + expect(bounds.values).toEqual([999.9999999999999]); + }); + }); describe('splitIntoSegments', function() { From 986dbb4a5a6ac2c6ec2c273fda96a960f92d6150 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Mon, 27 Jun 2016 16:26:04 +0200 Subject: [PATCH 413/593] Set the summary option to jasmine task to better analyse failed tests. This option displays a list of all failed tests and their failure messages. --- tasks/jasmine.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tasks/jasmine.js b/tasks/jasmine.js index 5e3fbc3a..88847db1 100644 --- a/tasks/jasmine.js +++ b/tasks/jasmine.js @@ -29,6 +29,7 @@ module.exports = function (grunt) { '<%= pkg.config.src %>/scripts/charts/pie.js' ], options: { + summary: true, specs: '<%= pkg.config.test %>/spec/**/spec-*.js', helpers: '<%= pkg.config.test %>/spec/**/helper-*.js', vendor: [ From 391d2f2629e414db6b3048719126020b5839ef68 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Fri, 1 Jul 2016 11:26:55 +0200 Subject: [PATCH 414/593] Add createGrid unit tests. --- src/scripts/core.js | 2 +- test/spec/spec-core.js | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 65678bda..64830470 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -69,7 +69,7 @@ var Chartist = { target[prop] = sourceProp; } } - }; + } return target; }; diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index e75c0e61..5a39f97d 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -466,4 +466,62 @@ describe('Chartist core', function() { }]); }); }); + + describe('createGrid', function() { + var group, axis, classes, eventEmitter, position, length, offset; + + beforeEach(function() { + eventEmitter = Chartist.EventEmitter(); + group = new Chartist.Svg('g'); + axis = { + units: { + pos : 'x' + }, + counterUnits: { + pos : 'y' + } + }; + classes = []; + position = 10; + length = 100; + offset = 20; + }); + + function onCreated(fn, done) { + eventEmitter.addEventHandler('draw', function(grid) { + fn(grid); + done(); + }); + Chartist.createGrid(position, 1, axis, offset, length, group, classes, eventEmitter); + } + + it('should add single grid line to group', function(done) { + onCreated(function() { + expect(group.querySelectorAll('line').svgElements.length).toBe(1); + }, done); + }); + + it('should draw line', function(done) { + onCreated(function() { + var line = group.querySelector('line'); + expect(line.attr('x1')).toBe('10'); + expect(line.attr('x2')).toBe('10'); + expect(line.attr('y1')).toBe('20'); + expect(line.attr('y2')).toBe('120'); + }, done); + }); + + it('should draw horizontal line', function(done) { + axis.units.pos = 'y'; + axis.counterUnits.pos = 'x'; + onCreated(function() { + var line = group.querySelector('line'); + expect(line.attr('y1')).toBe('10'); + expect(line.attr('y2')).toBe('10'); + expect(line.attr('x1')).toBe('20'); + expect(line.attr('x2')).toBe('120'); + }, done); + }); + + }); }); From 401731c99b6e0db185956b3d6ad958fd19ec3252 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Mon, 4 Jul 2016 09:28:00 +0200 Subject: [PATCH 415/593] Add grid background to line chart. --- src/scripts/charts/line.js | 12 +++- src/scripts/core.js | 25 ++++++++ src/styles/chartist.scss | 4 ++ src/styles/settings/_chartist-settings.scss | 2 + test/spec/spec-core.js | 50 ++++++++++++++++ test/spec/spec-line-chart.js | 65 +++++++++++++++++++++ 6 files changed, 156 insertions(+), 2 deletions(-) diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 30f60683..66fb6682 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -69,11 +69,13 @@ showPoint: true, // If the line chart should draw an area showArea: false, - // The base for the area chart that will be used to close the area shape (is normally 0) + // The base for the area chart that will be used to close the area shape (is normally 0) areaBase: 0, // 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. lineSmooth: true, - // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + // If the line chart should add a background fill to the .ct-grids group. + showGridBackground: false, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, @@ -99,6 +101,7 @@ area: 'ct-area', grid: 'ct-grid', gridGroup: 'ct-grids', + gridBackground: 'ct-grid-background', vertical: 'ct-vertical', horizontal: 'ct-horizontal', start: 'ct-start', @@ -148,6 +151,11 @@ axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + if (options.showGridBackground) { + + Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + // Draw the series data.raw.series.forEach(function(series, seriesIndex) { var seriesElement = seriesGroup.elem('g'); diff --git a/src/scripts/core.js b/src/scripts/core.js index 64830470..398cad1a 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -874,6 +874,31 @@ var Chartist = { ); }; + /** + * Creates a grid background rect and emits the draw event. + * + * @memberof Chartist.Core + * @param gridGroup + * @param chartRect + * @param className + * @param eventEmitter + */ + Chartist.createGridBackground = function (gridGroup, chartRect, className, eventEmitter) { + var gridBackground = gridGroup.elem('rect', { + x: chartRect.x1, + y: chartRect.y2, + width: chartRect.width(), + height: chartRect.height(), + }, className, true); + + // Event for grid background draw + eventEmitter.emit('draw', { + type: 'gridBackground', + group: gridGroup, + element: gridBackground + }); + }; + /** * Creates a label based on a projected value and an axis. * diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index 0f19ba05..e4726d8a 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -188,6 +188,10 @@ @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); } + .#{$ct-class-grid-background} { + fill: $ct-grid-background-fill; + } + .#{$ct-class-point} { @include ct-chart-point($ct-point-size, $ct-point-shape); } diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss index 21b92c13..4d0370eb 100644 --- a/src/styles/settings/_chartist-settings.scss +++ b/src/styles/settings/_chartist-settings.scss @@ -18,6 +18,7 @@ $ct-class-bar: ct-bar !default; $ct-class-slice-pie: ct-slice-pie !default; $ct-class-slice-donut: ct-slice-donut !default; $ct-class-grid: ct-grid !default; +$ct-class-grid-background: ct-grid-background !default; $ct-class-vertical: ct-vertical !default; $ct-class-horizontal: ct-horizontal !default; $ct-class-start: ct-start !default; @@ -37,6 +38,7 @@ $ct-text-line-height: 1; $ct-grid-color: rgba(0, 0, 0, 0.2) !default; $ct-grid-dasharray: 2px !default; $ct-grid-width: 1px !default; +$ct-grid-background-fill: none !default; // Line chart properties $ct-line-width: 4px !default; diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 5a39f97d..83a43e80 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -524,4 +524,54 @@ describe('Chartist core', function() { }); }); + + describe('createGridBackground', function() { + var group, chartRect, className, eventEmitter; + + beforeEach(function() { + eventEmitter = Chartist.EventEmitter(); + group = new Chartist.Svg('g'); + className = 'ct-test'; + chartRect = { + x1 : 5, + y2 : 10, + _width : 100, + _height : 50, + width : function() { return this._width; }, + height : function() { return this._height; }, + }; + }); + + function onCreated(fn, done) { + eventEmitter.addEventHandler('draw', function(data) { + fn(data); + done(); + }); + Chartist.createGridBackground(group, chartRect, className, eventEmitter); + } + + it('should add rect', function(done) { + onCreated(function() { + var rects = group.querySelectorAll('rect').svgElements; + expect(rects.length).toBe(1); + var rect = rects[0]; + expect(rect.attr('x')).toBe('5'); + expect(rect.attr('y')).toBe('10'); + expect(rect.attr('width')).toBe('100'); + expect(rect.attr('height')).toBe('50'); + expect(rect.classes()).toEqual(['ct-test']); + }, done); + }); + + it('should pass grid to event', function(done) { + onCreated(function(data) { + expect(data.type).toBe('gridBackground'); + var rect = data.element; + expect(rect.attr('x')).toBe('5'); + expect(rect.attr('y')).toBe('10'); + }, done); + }); + + + }); }); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index 96964f1a..21be7e5c 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -9,6 +9,71 @@ describe('Line chart tests', function () { }); + describe('grids', function() { + + var chart; + var options; + var data; + + beforeEach(function() { + data = { + series: [[ + { x: 1, y: 1 }, + { x: 3, y: 5 } + ]] + }; + options = { + axisX: { + type: Chartist.AutoScaleAxis, + onlyInteger: true + }, + axisY: { + type: Chartist.AutoScaleAxis, + onlyInteger: true + } + }; + }); + + function onCreated(fn) { + jasmine.getFixtures().set('
    '); + chart = new Chartist.Line('.ct-chart', data, options); + chart.on('created', fn); + } + + it('should contain ct-grids group', function(done) { + onCreated(function () { + expect($('g.ct-grids').length).toBe(1); + done(); + }); + }); + + it('should draw grid lines', function(done) { + onCreated(function () { + expect($('g.ct-grids line.ct-grid.ct-horizontal').length).toBe(3); + expect($('g.ct-grids line.ct-grid.ct-vertical').length).toBe(5); + done(); + }); + }); + + it('should draw grid background', function(done) { + options.showGridBackground = true; + onCreated(function () { + expect($('g.ct-grids rect.ct-grid-background').length).toBe(1); + done(); + }); + }); + + it('should not draw grid background if option set to false', function(done) { + options.showGridBackground = false; + onCreated(function () { + expect($('g.ct-grids rect.ct-grid-background').length).toBe(0); + done(); + }); + }); + + }); + + describe('ct:value attribute', function () { it('should contain x and y value for each datapoint', function (done) { jasmine.getFixtures().set('
    '); From 719f86188d2539d016c2c43dcd7dd89d7f5cf182 Mon Sep 17 00:00:00 2001 From: hansmaad Date: Mon, 4 Jul 2016 09:36:58 +0200 Subject: [PATCH 416/593] Add grid background to bar chart. --- src/scripts/charts/bar.js | 7 ++++ src/scripts/charts/line.js | 1 - test/spec/spec-bar-chart.js | 65 +++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 0e3c7fa4..cf132326 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -85,6 +85,8 @@ distributeSeries: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. reverseData: false, + // If the bar chart should add a background fill to the .ct-grids group. + showGridBackground: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', @@ -95,6 +97,7 @@ bar: 'ct-bar', grid: 'ct-grid', gridGroup: 'ct-grids', + gridBackground: 'ct-grid-background', vertical: 'ct-vertical', horizontal: 'ct-horizontal', start: 'ct-start', @@ -226,6 +229,10 @@ labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + if (options.showGridBackground) { + Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + // Draw the series data.raw.series.forEach(function(series, seriesIndex) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 66fb6682..862d2efa 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -152,7 +152,6 @@ axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); if (options.showGridBackground) { - Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); } diff --git a/test/spec/spec-bar-chart.js b/test/spec/spec-bar-chart.js index c726c4f7..bf1b21c6 100644 --- a/test/spec/spec-bar-chart.js +++ b/test/spec/spec-bar-chart.js @@ -9,6 +9,71 @@ describe('Bar chart tests', function() { }); + describe('grids', function() { + + var chart; + var options; + var data; + + beforeEach(function() { + data = { + series: [[ + { x: 1, y: 1 }, + { x: 3, y: 5 } + ]] + }; + options = { + axisX: { + type: Chartist.AutoScaleAxis, + onlyInteger: true + }, + axisY: { + type: Chartist.AutoScaleAxis, + onlyInteger: true + } + }; + }); + + function onCreated(fn) { + jasmine.getFixtures().set('
    '); + chart = new Chartist.Bar('.ct-chart', data, options); + chart.on('created', fn); + } + + it('should contain ct-grids group', function(done) { + onCreated(function () { + expect($('g.ct-grids').length).toBe(1); + done(); + }); + }); + + it('should draw grid lines', function(done) { + onCreated(function () { + expect($('g.ct-grids line.ct-grid.ct-horizontal').length).toBe(3); + expect($('g.ct-grids line.ct-grid.ct-vertical').length).toBe(6); + done(); + }); + }); + + it('should draw grid background', function(done) { + options.showGridBackground = true; + onCreated(function () { + expect($('g.ct-grids rect.ct-grid-background').length).toBe(1); + done(); + }); + }); + + it('should not draw grid background if option set to false', function(done) { + options.showGridBackground = false; + onCreated(function () { + expect($('g.ct-grids rect.ct-grid-background').length).toBe(0); + done(); + }); + }); + + }); + + describe('ct:value attribute', function() { it('should contain x and y value for each bar', function(done) { jasmine.getFixtures().set('
    '); From 6ab3c22a984760452ccf3cd77515bfcb47bf0eca Mon Sep 17 00:00:00 2001 From: Drew Atkinson Date: Sun, 24 Jul 2016 12:14:02 -0400 Subject: [PATCH 417/593] Adds grunt-assemble plugin to devDependencies --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 2ae8bd52..4b7d4343 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "devDependencies": { "assemble-dox": "0.0.2", "grunt": "^1.0.1", + "grunt-assemble": "^0.4.0", "grunt-concurrent": "^2.3.0", "grunt-contrib-clean": "^1.0.0", "grunt-contrib-concat": "^1.0.1", From 7ee0734162c97bc2495e315101f6dff54ef80345 Mon Sep 17 00:00:00 2001 From: Drew Atkinson Date: Sat, 6 Aug 2016 10:39:31 -0400 Subject: [PATCH 418/593] add Moment.js Timeseries Example to examples page --- bower.json | 3 +- site/data/pages/examples.yml | 10 ++++++ site/examples/example-timeseries-moment.js | 37 ++++++++++++++++++++++ site/layouts/default.hbs | 1 + 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 site/examples/example-timeseries-moment.js diff --git a/bower.json b/bower.json index be74fc1a..4588f231 100755 --- a/bower.json +++ b/bower.json @@ -18,7 +18,8 @@ "chartist-plugin-threshold": "~0.0.1", "chartist-plugin-fill-donut": "~0.0.1", "chartist-plugin-zoom": "~0.2.1", - "matchMedia": "~0.2.0" + "matchMedia": "~0.2.0", + "moment": "^2.14.1" }, "ignore": [ ".*", diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 28b28cc4..04b7a27e 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -121,6 +121,16 @@ sections: showArea and even the smoothing function can be overriden per series! And guess what? You can even override those series settings in the responsive configuration! Check the example code for more details. + - type: live-example + data: + title: Time Series with Moment.js + level: 4 + id: example-timeseries-moment + classes: ct-golden-section + intro: > + This example uses Moment.js in the label interpolation function + to format a date object. The fixed axis ensures that there is correct spacing between the data points, + and the number of labels is determined by the devisor. - title: Bar chart examples level: 3 items: diff --git a/site/examples/example-timeseries-moment.js b/site/examples/example-timeseries-moment.js new file mode 100644 index 00000000..4e79f992 --- /dev/null +++ b/site/examples/example-timeseries-moment.js @@ -0,0 +1,37 @@ +// Requires Moment.js + +var chart = new Chartist.Line('.ct-chart', { + series: [ + { + name: 'series-1', + data: [ + {x: new Date(143134652600), y: 53}, + {x: new Date(143234652600), y: 40}, + {x: new Date(143340052600), y: 45}, + {x: new Date(143366652600), y: 40}, + {x: new Date(143410652600), y: 20}, + {x: new Date(143508652600), y: 32}, + {x: new Date(143569652600), y: 18}, + {x: new Date(143579652600), y: 11} + ] + }, + { + name: 'series-2', + data: [ + {x: new Date(143134652600), y: 53}, + {x: new Date(143234652600), y: 35}, + {x: new Date(143334652600), y: 30}, + {x: new Date(143384652600), y: 30}, + {x: new Date(143568652600), y: 10} + ] + } + ] +}, { + axisX: { + type: Chartist.FixedScaleAxis, + divisor: 5, + labelInterpolationFnc: function(value) { + return moment(value).format('MMM D'); + } + } +}); \ No newline at end of file diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 5bd28a59..2bb8ee22 100755 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -38,6 +38,7 @@ + From d083f37826d17865657d7b9d14ba0e01c4adb6be Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 22 Aug 2016 10:00:48 -0400 Subject: [PATCH 419/593] Add amdModuleId Needed for webpacking scripts - sets name correctly --- tasks/umd.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tasks/umd.js b/tasks/umd.js index 1aa94191..a1cdf158 100644 --- a/tasks/umd.js +++ b/tasks/umd.js @@ -15,6 +15,7 @@ module.exports = function (grunt) { src: '<%= pkg.config.dist %>/chartist.js', objectToExport: 'Chartist', globalAlias: 'Chartist', + amdModuleId: 'Chartist', indent: ' ' } }; From 4ab6e685ca3abe11c8b001b25f9e5706daae3837 Mon Sep 17 00:00:00 2001 From: Max Knee Date: Mon, 22 Aug 2016 11:04:09 -0400 Subject: [PATCH 420/593] Switching from space to numbers --- tasks/umd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/umd.js b/tasks/umd.js index a1cdf158..cef46933 100644 --- a/tasks/umd.js +++ b/tasks/umd.js @@ -16,7 +16,7 @@ module.exports = function (grunt) { objectToExport: 'Chartist', globalAlias: 'Chartist', amdModuleId: 'Chartist', - indent: ' ' + indent: 2 } }; }; From a57988fc4eec25e08509036887cda8114772a9d2 Mon Sep 17 00:00:00 2001 From: Max Knee Date: Mon, 22 Aug 2016 11:08:43 -0400 Subject: [PATCH 421/593] Bumping .nvmrc version to match .travis.yml version --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 7fd9b020..9aeb5c2a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1,2 +1,2 @@ -v0.10.35 +v5.5.0 From 320ddd8e6b0a69e57e7ff6b0c7ba25602ae7df36 Mon Sep 17 00:00:00 2001 From: Larry Botha Date: Wed, 24 Aug 2016 09:26:02 +0200 Subject: [PATCH 422/593] replace browser-specific globals with 'this' to prevent node-runtime errors --- src/scripts/axes/auto-scale-axis.js | 7 +++++-- src/scripts/axes/axis.js | 7 +++++-- src/scripts/axes/fixed-scale-axis.js | 7 +++++-- src/scripts/axes/step-axis.js | 7 +++++-- src/scripts/base.js | 6 ++++-- src/scripts/charts/bar.js | 7 +++++-- src/scripts/charts/line.js | 7 +++++-- src/scripts/charts/pie.js | 7 +++++-- src/scripts/class.js | 4 ++-- src/scripts/core.js | 7 +++++-- src/scripts/event.js | 4 ++-- src/scripts/interpolation.js | 4 ++-- src/scripts/svg-path.js | 4 ++-- src/scripts/svg.js | 6 ++++-- 14 files changed, 56 insertions(+), 28 deletions(-) diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js index ebecb619..32b2e0fd 100644 --- a/src/scripts/axes/auto-scale-axis.js +++ b/src/scripts/axes/auto-scale-axis.js @@ -20,9 +20,12 @@ * @module Chartist.AutoScaleAxis */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); @@ -48,4 +51,4 @@ projectValue: projectValue }); -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 4920f360..2ecb28cd 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -1,7 +1,10 @@ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + var axisUnits = { x: { pos: 'x', @@ -113,4 +116,4 @@ Chartist.Axis.units = axisUnits; -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index bb42f9cc..07275257 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -18,9 +18,12 @@ * @module Chartist.FixedScaleAxis */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + function FixedScaleAxis(axisUnit, data, chartRect, options) { var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); this.divisor = options.divisor || 1; @@ -53,4 +56,4 @@ projectValue: projectValue }); -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index 014a4883..4167961e 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -14,9 +14,12 @@ * @module Chartist.StepAxis */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + function StepAxis(axisUnit, data, chartRect, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, @@ -36,4 +39,4 @@ projectValue: projectValue }); -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/base.js b/src/scripts/base.js index 1ca36a2a..e9034e5c 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -4,9 +4,11 @@ * @module Chartist.Base */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. @@ -186,4 +188,4 @@ supportsForeignObject: false }); -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 0e3c7fa4..2095c8b8 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -4,9 +4,12 @@ * @module Chartist.Bar */ /* global Chartist */ -(function(window, document, Chartist){ +(function(globalRoot, Chartist){ 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * Default options in bar charts. Expand the code view to see a detailed list of options with comments. * @@ -427,4 +430,4 @@ createChart: createChart }); -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 30f60683..3bee8538 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -6,9 +6,12 @@ * @module Chartist.Line */ /* global Chartist */ -(function(window, document, Chartist){ +(function(globalRoot, Chartist){ 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * Default options in line charts. Expand the code view to see a detailed list of options with comments. * @@ -408,4 +411,4 @@ createChart: createChart }); -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 091b35ff..eb150f81 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -4,9 +4,12 @@ * @module Chartist.Pie */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * Default options in line charts. Expand the code view to see a detailed list of options with comments. * @@ -345,4 +348,4 @@ determineAnchorPosition: determineAnchorPosition }); -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/class.js b/src/scripts/class.js index 30ae475c..b770fb95 100644 --- a/src/scripts/class.js +++ b/src/scripts/class.js @@ -4,7 +4,7 @@ * @module Chartist.Class */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; function listToArray(list) { @@ -108,4 +108,4 @@ cloneDefinitions: cloneDefinitions }; -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/core.js b/src/scripts/core.js index 9855a853..673e792f 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -7,9 +7,12 @@ var Chartist = { version: '<%= pkg.version %>' }; -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * This object contains all namespaces used within Chartist. * @@ -1064,4 +1067,4 @@ var Chartist = { return segments; }; -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/event.js b/src/scripts/event.js index 2b495f7b..d6fd8669 100644 --- a/src/scripts/event.js +++ b/src/scripts/event.js @@ -4,7 +4,7 @@ * @module Chartist.Event */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; Chartist.EventEmitter = function () { @@ -75,4 +75,4 @@ }; }; -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 62a358df..43da8db2 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -4,7 +4,7 @@ * @module Chartist.Interpolation */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; Chartist.Interpolation = {}; @@ -434,4 +434,4 @@ }; }; -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/svg-path.js b/src/scripts/svg-path.js index 06e5e286..f6724ff3 100644 --- a/src/scripts/svg-path.js +++ b/src/scripts/svg-path.js @@ -4,7 +4,7 @@ * @module Chartist.Svg.Path */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; /** @@ -382,4 +382,4 @@ Chartist.Svg.Path.elementDescriptions = elementDescriptions; Chartist.Svg.Path.join = join; -}(window, document, Chartist)); +}(this, Chartist)); diff --git a/src/scripts/svg.js b/src/scripts/svg.js index be20ade4..dfe2af50 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -4,9 +4,11 @@ * @module Chartist.Svg */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; + var document = globalRoot.document; + /** * 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. * @@ -584,4 +586,4 @@ Chartist.Svg.List = Chartist.Class.extend({ constructor: SvgList }); -}(window, document, Chartist)); +}(this, Chartist)); From 7002534868760b2ccf56c02e0b2f58b8a9149767 Mon Sep 17 00:00:00 2001 From: Yoann Bourdex Date: Sat, 27 Aug 2016 10:08:15 +0200 Subject: [PATCH 423/593] add link to vue-chartist --- site/data/pages/index.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 04c62798..783b03f0 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -240,6 +240,9 @@ sections: - - 'ChartistJSF' - Java Server Faces (Prime Faces) Component + - + -'vue-chartist' + - Vue plugin - title: Chart CSS animation example level: 3 items: From 1677380432842e833bbf6f9e32f06222c82f6fa2 Mon Sep 17 00:00:00 2001 From: Erik Lieben Date: Mon, 12 Sep 2016 10:05:37 +0200 Subject: [PATCH 424/593] Add aurelia-chartist to list of wrapper libraries. --- site/data/pages/index.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 783b03f0..3763ee48 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -243,6 +243,9 @@ sections: - -'vue-chartist' - Vue plugin + - + -'aurelia-chartist' + - Aurelia plugin - title: Chart CSS animation example level: 3 items: From 2bac3e247ee5a1f5863919a7f55849b6f663640c Mon Sep 17 00:00:00 2001 From: Alexander van Eck Date: Thu, 29 Sep 2016 09:01:18 +0200 Subject: [PATCH 425/593] set endAngle to zero when totalDataSum is zero. Fixes console errors for svg path creation. --- src/scripts/charts/pie.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 091b35ff..aa2384f9 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -163,7 +163,8 @@ (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) ].join(' ')); - var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. + var endAngle = (totalDataSum > 0 ? startAngle + dataArray[i] / totalDataSum * 360 : 0); // Use slight offset so there are no transparent hairline issues var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); From 1ec4ebf8946912a98cab7c507fe045e9eba792af Mon Sep 17 00:00:00 2001 From: Alexander van Eck Date: Thu, 29 Sep 2016 14:00:00 +0200 Subject: [PATCH 426/593] created empty values test to make sure Pie renders without NaN values and points. --- test/spec/spec-pie-chart.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index 6108d78f..e6480589 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -252,6 +252,39 @@ describe('Pie chart tests', function() { }); }); + describe('Pie with empty values', function() { + var data; + + beforeEach(function() { + data = { + series: [0, 0, 0] + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var chart = new Chartist.Pie('.ct-chart', data, {}); + chart.on('created', callback); + } + + it('Pie should render without NaN values and points', function(done) { + onCreated(function() { + var slices = $('.ct-slice-pie'); + + expect(slices.length).toBe(3); + + expect(slices.eq(2).attr('ct:value')).toBe('0'); + expect(slices.eq(1).attr('ct:value')).toBe('0'); + expect(slices.eq(0).attr('ct:value')).toBe('0'); + + expect(slices.eq(2).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); + expect(slices.eq(1).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); + expect(slices.eq(0).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); + done(); + }); + }); + }); + describe('Pie with some empty values configured not to be ignored', function() { var data, options; From 4f3f7624c1af0c05e5485796a9e6a8c22712119c Mon Sep 17 00:00:00 2001 From: Alexander van Eck Date: Fri, 30 Sep 2016 01:10:39 +0200 Subject: [PATCH 427/593] If axisOptions.position is not start set Label className to 'end' classname --- src/scripts/axes/axis.js | 2 +- test/spec/spec-line-chart.js | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 4920f360..72c08592 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -97,7 +97,7 @@ Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [ chartOptions.classNames.label, chartOptions.classNames[this.units.dir], - chartOptions.classNames[axisOptions.position] + (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']) ], useForeignObject, eventEmitter); } }.bind(this)); diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index 21be7e5c..21a755b8 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -73,6 +73,54 @@ describe('Line chart tests', function () { }); + describe('AxisY position tests', function() { + var options; + var data; + + beforeEach(function() { + data = { + series: [[ + { x: 1, y: 1 }, + { x: 3, y: 5 } + ]] + }; + options = {}; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var chart = new Chartist.Line('.ct-chart', data, options); + chart.on('created', callback); + } + + it('class should be ct-start if position start', function(done) { + options = { + axisY: { + position: 'start' + } + } + onCreated(function() { + $('.ct-label.ct-vertical').each(function() { + expect($(this).attr('class')).toBe('ct-label ct-vertical ct-start'); + }); + done(); + }); + }); + + it('class should be ct-end if position is any other value than start', function(done) { + options = { + axisY: { + position: 'right' + } + } + onCreated(function() { + $('.ct-label.ct-vertical').each(function() { + expect($(this).attr('class')).toBe('ct-label ct-vertical ct-end'); + }); + done(); + }); + }); + }); describe('ct:value attribute', function () { it('should contain x and y value for each datapoint', function (done) { From ff5ebec38d4b2d2a13987095ffaf7f5780bf344a Mon Sep 17 00:00:00 2001 From: Joao Milton Date: Tue, 4 Oct 2016 20:45:37 +0000 Subject: [PATCH 428/593] Fix function StepAxis() returning NaN --- src/scripts/axes/step-axis.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index 014a4883..8db1a3db 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -24,7 +24,8 @@ options.ticks, options); - this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0)); + var calc = (options.ticks.length - (options.stretch ? 1 : 0)); + this.stepLength = this.axisLength / (calc === 0 ? 1 : calc); } function projectValue(value, index) { From ea8ec8b42de2108a3d08c1b3b77ce4100fd2d646 Mon Sep 17 00:00:00 2001 From: Joao Milton Date: Tue, 4 Oct 2016 20:46:27 +0000 Subject: [PATCH 429/593] Create test --- test/spec/spec-line-chart.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index 21be7e5c..bb034d3a 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -502,4 +502,24 @@ describe('Line chart tests', function () { }); }); }); + + describe('x1 and x2 attribute', function () { + it('should contain just a datapoint', function (done) { + jasmine.getFixtures().set('
    '); + + var chart = new Chartist.Line('.ct-chart', { + series: [[ + {x: 1, y: 2} + ]] + }, { + fullWidth: true + }); + + chart.on('created', function () { + expect($('.ct-point').eq(0).attr('x1')).not.toBe('NaN'); + expect($('.ct-point').eq(0).attr('x2')).not.toBe('NaN'); + done(); + }); + }); + }); }); From 0fc6f9f48c70c4c76927601f9b547ee454a29843 Mon Sep 17 00:00:00 2001 From: James Watmuff Date: Wed, 19 Oct 2016 23:39:02 +1100 Subject: [PATCH 430/593] Fix handling of holes in interpolation for multi-value series --- site/examples/example-line-data-fill-holes.js | 3 ++- site/examples/example-line-data-holes.js | 3 ++- src/scripts/axes/auto-scale-axis.js | 2 +- src/scripts/axes/fixed-scale-axis.js | 2 +- src/scripts/core.js | 16 +++++++++------- src/scripts/interpolation.js | 2 +- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/site/examples/example-line-data-fill-holes.js b/site/examples/example-line-data-fill-holes.js index 6c8e74b1..0faae16d 100644 --- a/site/examples/example-line-data-fill-holes.js +++ b/site/examples/example-line-data-fill-holes.js @@ -3,7 +3,8 @@ var chart = new Chartist.Line('.ct-chart', { series: [ [5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9], [10, 15, null, 12, null, 10, 12, 15, null, null, 12, null, 14, null, null, null], - [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null] + [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null], + [{x:3, y: 3},{x: 4, y: 3}, {x: 5, y: undefined}, {x: 6, y: 4}, {x: 7, y: null}, {x: 8, y: 4}, {x: 9, y: 4}] ] }, { fullWidth: true, diff --git a/site/examples/example-line-data-holes.js b/site/examples/example-line-data-holes.js index 526f300f..60027417 100644 --- a/site/examples/example-line-data-holes.js +++ b/site/examples/example-line-data-holes.js @@ -3,7 +3,8 @@ var chart = new Chartist.Line('.ct-chart', { series: [ [5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9], [10, 15, null, 12, null, 10, 12, 15, null, null, 12, null, 14, null, null, null], - [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null] + [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null], + [{x:3, y: 3},{x: 4, y: 3}, {x: 5, y: undefined}, {x: 6, y: 4}, {x: 7, y: null}, {x: 8, y: 4}, {x: 9, y: 4}] ] }, { fullWidth: true, diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js index ebecb619..92942dc8 100644 --- a/src/scripts/axes/auto-scale-axis.js +++ b/src/scripts/axes/auto-scale-axis.js @@ -40,7 +40,7 @@ } function projectValue(value) { - return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos, 0) - this.bounds.min) / this.bounds.range; } Chartist.AutoScaleAxis = Chartist.Axis.extend({ diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index bb42f9cc..e4e8d20a 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -45,7 +45,7 @@ } function projectValue(value) { - return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos, 0) - this.range.min) / (this.range.max - this.range.min); } Chartist.FixedScaleAxis = Chartist.Axis.extend({ diff --git a/src/scripts/core.js b/src/scripts/core.js index 398cad1a..3054d7e5 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -586,7 +586,7 @@ var Chartist = { * @returns {Boolean} */ Chartist.isNum = function(value) { - return !isNaN(value) && isFinite(value); + return (typeof value === "number" || typeof value === "string") && !isNaN(value) && isFinite(value); }; /** @@ -608,23 +608,24 @@ var Chartist = { * @returns {*} */ Chartist.getNumberOrUndefined = function(value) { - return isNaN(+value) ? undefined : +value; + return Chartist.isNum(value) ? +value : undefined; }; /** - * 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 undefined. + * 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`. * * @param value * @param dimension + * @param defaultValue * @returns {*} */ - Chartist.getMultiValue = function(value, dimension) { + Chartist.getMultiValue = function(value, dimension, defaultValue) { if(Chartist.isNum(value)) { return +value; } else if(value) { - return value[dimension || 'y'] || 0; + return Chartist.isFalseyButZero(value[dimension || 'y']) ? defaultValue : value[dimension || 'y']; } else { - return 0; + return defaultValue; } }; @@ -1068,7 +1069,8 @@ var Chartist = { for(var i = 0; i < pathCoordinates.length; i += 2) { // If this value is a "hole" we set the hole flag - if(valueData[i / 2].value === undefined) { + if(Chartist.getMultiValue(valueData[i / 2].value) === undefined) { + // if(valueData[i / 2].value === undefined) { if(!options.fillHoles) { hole = true; } diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index 62a358df..b1e20810 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -40,7 +40,7 @@ var currY = pathCoordinates[i + 1]; var currData = valueData[i / 2]; - if(currData.value !== undefined) { + if(Chartist.getMultiValue(currData.value) !== undefined) { if(hole) { path.move(currX, currY, false, currData); From e18c3a8de405ee9dd325afc7a88a14e535693f4b Mon Sep 17 00:00:00 2001 From: Alexander van Eck Date: Fri, 30 Sep 2016 00:05:26 +0200 Subject: [PATCH 431/593] Added a check when calculating stepLength to only stretch ticksLength if > 1. Added test to Axes and LineChart --- test/spec/spec-axes.js | 30 ++++++++++++++++++++++++++++++ test/spec/spec-line-chart.js | 26 ++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/test/spec/spec-axes.js b/test/spec/spec-axes.js index 8afd9dc1..892b2313 100644 --- a/test/spec/spec-axes.js +++ b/test/spec/spec-axes.js @@ -1,6 +1,36 @@ describe('Axes tests', function() { 'use strict'; + describe('StepAxis projectValue should not return NaN', function() { + it('should return 0 if options.ticks.length == 1', function() { + var ticks = [1], + axisUnit = { + 'pos':'y', + 'len':'height', + 'dir':'vertical', + 'rectStart':'y2', + 'rectEnd':'y1', + 'rectOffset':'x1' + }, + data = { + 'raw': { + 'series':[[1]] + } + }, + chartRect = { + 'y2':0, + 'y1':15, + 'x1':50, + 'x2':100 + }, + options = { + 'ticks': ticks + }, + stepAxis = new Chartist.StepAxis(axisUnit, data, chartRect, options); + expect(stepAxis.stepLength).toEqual(15); + }); + }); + describe('fixed scale axis', function () { it('should order the tick array', function() { diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index bb034d3a..c5a3ab78 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -413,6 +413,32 @@ describe('Line chart tests', function () { }); }); + describe('Single value data tests', function() { + var data; + + beforeEach(function() { + data = { + labels: [1], + series: [[1]] + }; + }); + + function onCreated(callback) { + jasmine.getFixtures().set('
    '); + var chart = new Chartist.Line('.ct-chart', data); + chart.on('created', callback); + } + + it('should render without NaN values and points', function(done) { + onCreated(function() { + expect($('.ct-line').eq(0).attr('d')).toBe('M50,15'); + expect($('.ct-point').eq(0).attr('x1')).toBe('50'); + expect($('.ct-point').eq(0).attr('x2')).toBe('50.01'); + done(); + }); + }); + }); + describe('Empty data tests', function () { it('should render empty grid with no data', function (done) { jasmine.getFixtures().set('
    '); From fd1dac175f1f1dec4f4ded005baed4588699881f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Oct 2016 18:19:19 +0200 Subject: [PATCH 432/593] Fixed line chart test formatting --- test/spec/spec-line-chart.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/spec/spec-line-chart.js b/test/spec/spec-line-chart.js index 543a4e70..7998b2ec 100644 --- a/test/spec/spec-line-chart.js +++ b/test/spec/spec-line-chart.js @@ -10,7 +10,7 @@ describe('Line chart tests', function () { }); describe('grids', function() { - + var chart; var options; var data; @@ -35,14 +35,14 @@ describe('Line chart tests', function () { }); function onCreated(fn) { - jasmine.getFixtures().set('
    '); + jasmine.getFixtures().set('
    '); chart = new Chartist.Line('.ct-chart', data, options); - chart.on('created', fn); + chart.on('created', fn); } it('should contain ct-grids group', function(done) { onCreated(function () { - expect($('g.ct-grids').length).toBe(1); + expect($('g.ct-grids').length).toBe(1); done(); }); }); @@ -50,7 +50,7 @@ describe('Line chart tests', function () { it('should draw grid lines', function(done) { onCreated(function () { expect($('g.ct-grids line.ct-grid.ct-horizontal').length).toBe(3); - expect($('g.ct-grids line.ct-grid.ct-vertical').length).toBe(5); + expect($('g.ct-grids line.ct-grid.ct-vertical').length).toBe(5); done(); }); }); @@ -98,7 +98,7 @@ describe('Line chart tests', function () { axisY: { position: 'start' } - } + }; onCreated(function() { $('.ct-label.ct-vertical').each(function() { expect($(this).attr('class')).toBe('ct-label ct-vertical ct-start'); @@ -112,7 +112,7 @@ describe('Line chart tests', function () { axisY: { position: 'right' } - } + }; onCreated(function() { $('.ct-label.ct-vertical').each(function() { expect($(this).attr('class')).toBe('ct-label ct-vertical ct-end'); @@ -576,11 +576,11 @@ describe('Line chart tests', function () { }); }); }); - + describe('x1 and x2 attribute', function () { it('should contain just a datapoint', function (done) { jasmine.getFixtures().set('
    '); - + var chart = new Chartist.Line('.ct-chart', { series: [[ {x: 1, y: 2} @@ -588,7 +588,7 @@ describe('Line chart tests', function () { }, { fullWidth: true }); - + chart.on('created', function () { expect($('.ct-point').eq(0).attr('x1')).not.toBe('NaN'); expect($('.ct-point').eq(0).attr('x2')).not.toBe('NaN'); From 8916ee643b5e8ab045406be93c3f83085e9f712a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Oct 2016 18:20:31 +0200 Subject: [PATCH 433/593] Added new LTS node version and included NPM run scripts, fixes #803 --- .nvmrc | 2 +- package.json | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.nvmrc b/.nvmrc index 9aeb5c2a..be628fe2 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1,2 +1,2 @@ -v5.5.0 +v6.9.0 diff --git a/package.json b/package.json index 4b7d4343..58692e3b 100644 --- a/package.json +++ b/package.json @@ -73,10 +73,15 @@ "time-grunt": "^1.0.0" }, "engines": { - "node": ">=5.5.0" + "node": ">=6.9.0" }, "scripts": { - "test": "grunt test" + "start": "./node_modules/.bin/grunt", + "test": "./node_modules/.bin/grunt test", + "dev": "./node_modules/.bin/grunt dev", + "build": "./node_modules/.bin/grunt build", + "preview": "./node_modules/.bin/grunt preview", + "public": "./node_modules/.bin/grunt public" }, "config": { "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> 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", From 05a607422f383c37007a084faa708b1bfc7631c6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Oct 2016 19:13:06 +0200 Subject: [PATCH 434/593] Fixing bower issues with minified main files --- bower.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 4588f231..8da2694a 100755 --- a/bower.json +++ b/bower.json @@ -1,8 +1,8 @@ { "name": "chartist", "main": [ - "./dist/chartist.min.js", - "./dist/chartist.min.css" + "./dist/chartist.js", + "./dist/chartist.css" ], "devDependencies": { "snap.svg": "~0.3.0", From 2d83da5a2c6ec628c643db2cbc787a38db52aa05 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Oct 2016 19:22:59 +0200 Subject: [PATCH 435/593] Refactored isNum core function to more meaningful logic --- src/scripts/charts/bar.js | 2 +- src/scripts/charts/line.js | 6 +++--- src/scripts/core.js | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index cf132326..75595d62 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -352,7 +352,7 @@ // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','), + 'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','), 'ct:meta': Chartist.getMetaData(series, valueIndex) }); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 862d2efa..d014aeae 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -141,8 +141,8 @@ if(options.axisY.type === undefined) { axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { - high: Chartist.isNum(options.high) ? options.high : options.axisY.high, - low: Chartist.isNum(options.low) ? options.low : options.axisY.low + high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high, + low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low })); } else { axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); @@ -213,7 +213,7 @@ x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','), 'ct:meta': pathElement.data.meta }); diff --git a/src/scripts/core.js b/src/scripts/core.js index 3054d7e5..e7534a7b 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -579,14 +579,14 @@ var Chartist = { }; /** - * Checks if the value is a valid number or string with a number. + * 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. * * @memberof Chartist.Core * @param value * @returns {Boolean} */ - Chartist.isNum = function(value) { - return (typeof value === "number" || typeof value === "string") && !isNaN(value) && isFinite(value); + Chartist.isNumeric = function(value) { + return value === null ? false : isFinite(value); }; /** @@ -608,7 +608,7 @@ var Chartist = { * @returns {*} */ Chartist.getNumberOrUndefined = function(value) { - return Chartist.isNum(value) ? +value : undefined; + return Chartist.isNumeric(value) ? +value : undefined; }; /** @@ -620,7 +620,7 @@ var Chartist = { * @returns {*} */ Chartist.getMultiValue = function(value, dimension, defaultValue) { - if(Chartist.isNum(value)) { + if(Chartist.isNumeric(value)) { return +value; } else if(value) { return Chartist.isFalseyButZero(value[dimension || 'y']) ? defaultValue : value[dimension || 'y']; From 8ad40d1b0d3ace40420230cde2783e704e41e82f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Oct 2016 22:15:53 +0200 Subject: [PATCH 436/593] Cleanup of data normalization changes #633 and allows Date object and boolens as values --- src/scripts/axes/auto-scale-axis.js | 2 +- src/scripts/axes/fixed-scale-axis.js | 2 +- src/scripts/core.js | 70 +++++++++++++++++++++------ test/spec/spec-core.js | 72 ++++++++++++++++++---------- 4 files changed, 104 insertions(+), 42 deletions(-) diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js index 92942dc8..ebecb619 100644 --- a/src/scripts/axes/auto-scale-axis.js +++ b/src/scripts/axes/auto-scale-axis.js @@ -40,7 +40,7 @@ } function projectValue(value) { - return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos, 0) - this.bounds.min) / this.bounds.range; + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; } Chartist.AutoScaleAxis = Chartist.Axis.extend({ diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index e4e8d20a..bb42f9cc 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -45,7 +45,7 @@ } function projectValue(value) { - return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos, 0) - this.range.min) / (this.range.max - this.range.min); + return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); } Chartist.FixedScaleAxis = Chartist.Axis.extend({ diff --git a/src/scripts/core.js b/src/scripts/core.js index e7534a7b..2651e4ce 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -364,6 +364,31 @@ var Chartist = { return data; }; + /** + * This function safely checks if an objects has an owned property. + * + * @param {Object} object The object where to check for a property + * @param {string} property The property name + * @returns {boolean} Returns true if the object owns the specified property + */ + Chartist.safeHasProperty = function(object, property) { + return object !== null && + typeof object === 'object' && + object.hasOwnProperty(property); + }; + + /** + * Checks if a value is considered a hole in the data series. + * + * @param {*} value + * @returns {boolean} True if the value is considered a data hole + */ + Chartist.isDataHoleValue = function(value) { + return value === null || + value === undefined || + (typeof value === 'number' && isNaN(value)); + }; + /** * Reverses the series, labels and series data arrays. * @@ -387,8 +412,8 @@ var Chartist = { * * @memberof Chartist.Core * @param {Object} data The series object that contains the data to be visualized in the chart - * @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. - * @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. + * @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. + * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ Chartist.getDataArray = function (data, reverse, multi) { @@ -403,14 +428,21 @@ var Chartist = { // Recursively walks through nested arrays and convert string values to numbers and objects with value properties // to values. Check the tests in data core -> data normalization for a detailed specification of expected values function recursiveConvert(value) { - if(Chartist.isFalseyButZero(value)) { - // This is a hole in data and we should return undefined - return undefined; - } else if((value.data || value) instanceof Array) { - return (value.data || value).map(recursiveConvert); - } else if(value.hasOwnProperty('value')) { + if(Chartist.safeHasProperty(value, 'value')) { + // We are dealing with value object notation so we need to recurse on value property return recursiveConvert(value.value); + } else if(Chartist.safeHasProperty(value, 'data')) { + // We are dealing with series object notation so we need to recurse on data property + return recursiveConvert(value.data); + } else if(value instanceof Array) { + // Data is of type array so we need to recurse on the series + return value.map(recursiveConvert); + } else if(Chartist.isDataHoleValue(value)) { + // We're dealing with a hole in the data and therefore need to return undefined + // We're also returning undefined for multi value output + return undefined; } else { + // We need to prepare multi value output (x and y data) if(multi) { var multiValue = {}; @@ -429,6 +461,7 @@ var Chartist = { return multiValue; } else { + // We can return simple data return Chartist.getNumberOrUndefined(value); } } @@ -611,21 +644,30 @@ var Chartist = { return Chartist.isNumeric(value) ? +value : undefined; }; + /** + * Checks if provided value object is multi value (contains x or y properties) + * + * @memberof Chartist.Core + * @param value + */ + Chartist.isMultiValue = function(value) { + return typeof value === 'object' && ('x' in value || 'y' in value); + }; + /** * 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`. * + * @memberof Chartist.Core * @param value * @param dimension * @param defaultValue * @returns {*} */ - Chartist.getMultiValue = function(value, dimension, defaultValue) { - if(Chartist.isNumeric(value)) { - return +value; - } else if(value) { - return Chartist.isFalseyButZero(value[dimension || 'y']) ? defaultValue : value[dimension || 'y']; + Chartist.getMultiValue = function(value, dimension) { + if(Chartist.isMultiValue(value)) { + return Chartist.getNumberOrUndefined(value[dimension || 'y']); } else { - return defaultValue; + return Chartist.getNumberOrUndefined(value); } }; diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 83a43e80..61954109 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -214,6 +214,26 @@ describe('Chartist core', function() { ]] ); }); + + it('should normalize boolean series correctly', function() { + var data = { + series: [true, false, false, true] + }; + + expect(Chartist.getDataArray(data)).toEqual( + [1, 0, 0, 1] + ); + }); + + it('should normalize date series correctly', function() { + var data = { + series: [new Date(0), new Date(1), new Date(2), new Date(3)] + }; + + expect(Chartist.getDataArray(data)).toEqual( + [0, 1, 2, 3] + ); + }); }); describe('padding normalization tests', function () { @@ -279,9 +299,9 @@ describe('Chartist core', function() { }); }); }); - + describe('quantity', function() { - + it('should return value for numbers', function() { expect(Chartist.quantity(100)).toEqual({ value: 100 }); expect(Chartist.quantity(0)).toEqual({ value: 0 }); @@ -289,28 +309,28 @@ describe('Chartist core', function() { expect(Chartist.quantity(null)).toEqual({ value: null }); expect(Chartist.quantity(undefined)).toEqual({ value: undefined }); }); - + it('should return value without unit from string', function() { expect(Chartist.quantity('100')).toEqual({ value: 100, unit : undefined }); expect(Chartist.quantity('0')).toEqual({ value: 0, unit : undefined }); }); - + it('should return value and unit from string', function() { expect(Chartist.quantity('100%')).toEqual({ value: 100, unit :'%' }); expect(Chartist.quantity('100 %')).toEqual({ value: 100, unit :'%' }); expect(Chartist.quantity('0px')).toEqual({ value: 0, unit: 'px' }); }); - + }); - + describe('getBounds', function() { - + it('should return 10 steps', function() { var bounds = Chartist.getBounds(100, { high: 10, low: 1 }, 10, false); expect(bounds.min).toBe(1); expect(bounds.max).toBe(10); expect(bounds.values).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); + }); it('should return 5 steps', function() { var bounds = Chartist.getBounds(100, { high: 10, low: 1 }, 20, false); @@ -318,29 +338,29 @@ describe('Chartist core', function() { expect(bounds.max).toBe(10); expect(bounds.values).toEqual([1, 3, 5, 7, 9]); // Is this correct behaviour? Should it include 10? - }); - + }); + it('should return non integer steps', function() { var bounds = Chartist.getBounds(100, { high: 2, low: 1 }, 20, false); expect(bounds.min).toBe(1); expect(bounds.max).toBe(2); expect(bounds.values).toEqual([ 1, 1.25, 1.5, 1.75, 2 ]); }); - + it('should return integer steps only', function() { var bounds = Chartist.getBounds(100, { high: 3, low: 1 }, 20, true); expect(bounds.min).toBe(1); expect(bounds.max).toBe(3); expect(bounds.values).toEqual([ 1, 2, 3 ]); }); - + it('should return single integer step', function() { var bounds = Chartist.getBounds(100, { high: 2, low: 1 }, 20, true); expect(bounds.min).toBe(1); expect(bounds.max).toBe(2); expect(bounds.values).toEqual([ 1, 2,]); }); - + it('should floor/ceil min/max', function() { var bounds = Chartist.getBounds(100, { high: 9.9, low: 1.01 }, 20, false); expect(bounds.min).toBe(1); @@ -348,28 +368,28 @@ describe('Chartist core', function() { expect(bounds.values).toEqual([1, 3, 5, 7, 9]); // Is this correct behaviour? Should it include 10? }); - + it('should floor/ceil min/max for non integers', function() { var bounds = Chartist.getBounds(100, { high: 2.9, low: 1.01 }, 20, false); expect(bounds.min).toBe(1); expect(bounds.max).toBe(3); expect(bounds.values).toEqual([1, 1.5, 2, 2.5, 3]); }); - + it('should floor/ceil min/max if integers only', function() { var bounds = Chartist.getBounds(100, { high: 2.9, low: 1.01 }, 20, true); expect(bounds.min).toBe(1); expect(bounds.max).toBe(3); expect(bounds.values).toEqual([1, 2, 3]); }); - + it('should return neg and pos values', function() { var bounds = Chartist.getBounds(100, { high: 1.9, low: -0.9 }, 20, false); expect(bounds.min).toBe(-1); expect(bounds.max).toBe(2); expect(bounds.values).toEqual([-1, 0, 1, 2]); }); - + it('should return two steps if no space', function() { var bounds = Chartist.getBounds(100, { high: 5, low: 0 }, 45, false); expect(bounds.min).toBe(0); @@ -377,7 +397,7 @@ describe('Chartist core', function() { expect(bounds.values).toEqual([0, 4]); // Is this correct behaviour? Should it be [0, 5]? }); - + it('should return single step if no space', function() { var bounds = Chartist.getBounds(100, { high: 5, low: 0 }, 80, false); expect(bounds.min).toBe(0); @@ -385,7 +405,7 @@ describe('Chartist core', function() { expect(bounds.values).toEqual([0]); // Is this correct behaviour? Should it be [0, 5]? }); - + it('should return single step if range is less than epsilon', function() { var bounds = Chartist.getBounds(100, { high: 1.0000000000000002, low: 1 }, 20, false); expect(bounds.min).toBe(1); @@ -394,7 +414,7 @@ describe('Chartist core', function() { expect(bounds.high).toBe(1.0000000000000002); expect(bounds.values).toEqual([1]); }); - + it('should return single step if range is less than smallest increment', function() { var bounds = Chartist.getBounds(613.234375, { high: 1000.0000000000001, low: 999.9999999999997 }, 50, false); expect(bounds.min).toBe(999.9999999999999); @@ -480,7 +500,7 @@ describe('Chartist core', function() { counterUnits: { pos : 'y' } - }; + }; classes = []; position = 10; length = 100; @@ -498,7 +518,7 @@ describe('Chartist core', function() { it('should add single grid line to group', function(done) { onCreated(function() { expect(group.querySelectorAll('line').svgElements.length).toBe(1); - }, done); + }, done); }); it('should draw line', function(done) { @@ -533,7 +553,7 @@ describe('Chartist core', function() { group = new Chartist.Svg('g'); className = 'ct-test'; chartRect = { - x1 : 5, + x1 : 5, y2 : 10, _width : 100, _height : 50, @@ -552,7 +572,7 @@ describe('Chartist core', function() { it('should add rect', function(done) { onCreated(function() { - var rects = group.querySelectorAll('rect').svgElements; + var rects = group.querySelectorAll('rect').svgElements; expect(rects.length).toBe(1); var rect = rects[0]; expect(rect.attr('x')).toBe('5'); @@ -560,13 +580,13 @@ describe('Chartist core', function() { expect(rect.attr('width')).toBe('100'); expect(rect.attr('height')).toBe('50'); expect(rect.classes()).toEqual(['ct-test']); - }, done); + }, done); }); it('should pass grid to event', function(done) { onCreated(function(data) { expect(data.type).toBe('gridBackground'); - var rect = data.element; + var rect = data.element; expect(rect.attr('x')).toBe('5'); expect(rect.attr('y')).toBe('10'); }, done); From f74f60c03acc09c7e98b46c97392221edcf50c9f Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 21 Oct 2016 22:24:56 +0200 Subject: [PATCH 437/593] Added correct meta data emission in events, fixes #722 --- src/scripts/charts/bar.js | 6 ++++-- src/scripts/charts/line.js | 3 ++- src/scripts/core.js | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 75595d62..699c7521 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -349,18 +349,20 @@ positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2); positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); + + var metaData = Chartist.getMetaData(series, valueIndex); // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','), - 'ct:meta': Chartist.getMetaData(series, valueIndex) + 'ct:meta': Chartist.serialize(metaData) }); this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', value: value, index: valueIndex, - meta: Chartist.getMetaData(series, valueIndex), + meta: metaData, series: series, seriesIndex: seriesIndex, axisX: axisX, diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index d014aeae..3fbb3d9c 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -214,7 +214,7 @@ y2: pathElement.y }, options.classNames.point).attr({ 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','), - 'ct:meta': pathElement.data.meta + 'ct:meta': Chartist.serialize(pathElement.data.meta) }); this.eventEmitter.emit('draw', { @@ -247,6 +247,7 @@ index: seriesIndex, series: series, seriesIndex: seriesIndex, + seriesMeta: series.meta, axisX: axisX, axisY: axisY, group: seriesElement, diff --git a/src/scripts/core.js b/src/scripts/core.js index 2651e4ce..681bf2c8 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -496,7 +496,7 @@ var Chartist = { Chartist.getMetaData = function(series, index) { var value = series.data ? series.data[index] : series[index]; - return value ? Chartist.serialize(value.meta) : undefined; + return value ? value.meta : undefined; }; /** From 4a636bc7fb1add702ebdd83e9dc383bd7bf91d43 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 22 Oct 2016 00:36:37 +0200 Subject: [PATCH 438/593] Cleanup refactoring for data management and normalization, fixes #754 --- src/scripts/axes/auto-scale-axis.js | 2 +- src/scripts/axes/fixed-scale-axis.js | 2 +- src/scripts/base.js | 8 +++- src/scripts/charts/bar.js | 60 ++++++++++++------------- src/scripts/charts/line.js | 32 ++++++-------- src/scripts/charts/pie.js | 38 ++++++++++------ src/scripts/core.js | 65 ++++++++++++++-------------- test/spec/spec-axes.js | 13 +----- 8 files changed, 113 insertions(+), 107 deletions(-) diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js index ebecb619..808bd88c 100644 --- a/src/scripts/axes/auto-scale-axis.js +++ b/src/scripts/axes/auto-scale-axis.js @@ -25,7 +25,7 @@ function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options - var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); this.range = { min: this.bounds.min, diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index bb42f9cc..a6e2022c 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -22,7 +22,7 @@ 'use strict'; function FixedScaleAxis(axisUnit, data, chartRect, options) { - var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return highLow.low + (highLow.high - highLow.low) / this.divisor * index; diff --git a/src/scripts/base.js b/src/scripts/base.js index 1ca36a2a..3c17d1d1 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -23,7 +23,9 @@ */ function update(data, options, override) { if(data) { - this.data = data; + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; // Event for data transformation that allows to manipulate the data before it gets rendered in the charts this.eventEmitter.emit('data', { type: 'update', @@ -143,7 +145,9 @@ */ function Base(query, data, defaultOptions, options, responsiveOptions) { this.container = Chartist.querySelector(query); - this.data = data; + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; this.defaultOptions = defaultOptions; this.options = options; this.responsiveOptions = responsiveOptions; diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 699c7521..701cd11f 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -110,16 +110,18 @@ * */ function createChart(options) { - this.data = Chartist.normalizeData(this.data); - var data = { - raw: this.data, - normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { - return [value]; - }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y') - }; - + var data; var highLow; + if(options.distributeSeries) { + data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + data.normalized.series = data.normalized.series.map(function(value) { + return [value]; + }); + } else { + data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + } + // Create new svg element this.svg = Chartist.createSvg( this.container, @@ -133,9 +135,9 @@ var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); - if(options.stackBars && data.normalized.length !== 0) { + if(options.stackBars && data.normalized.series.length !== 0) { // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = Chartist.serialMap(data.normalized, function serialSums() { + var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { return value; }).reduce(function(prev, curr) { @@ -150,7 +152,7 @@ referenceValue: 0 }), options.horizontalBars ? 'x' : 'y'); } else { - highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, { + highLow = Chartist.getHighLow(data.normalized.series, Chartist.extend({}, options, { referenceValue: 0 }), options.horizontalBars ? 'x' : 'y'); } @@ -170,51 +172,51 @@ if(options.distributeSeries && options.stackBars) { // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should // use only the first label for the step axis - labelAxisTicks = data.raw.labels.slice(0, 1); + labelAxisTicks = data.normalized.labels.slice(0, 1); } else { // If distributed series are enabled but stacked bars aren't, we should use the series labels // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array // as the bars are normalized - labelAxisTicks = data.raw.labels; + labelAxisTicks = data.normalized.labels; } // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { if(options.axisX.type === undefined) { - valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, referenceValue: 0 })); } else { - valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, referenceValue: 0 })); } if(options.axisY.type === undefined) { - labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, { ticks: labelAxisTicks }); } else { - labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY); } } else { if(options.axisX.type === undefined) { - labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, { ticks: labelAxisTicks }); } else { - labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX); } if(options.axisY.type === undefined) { - valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); } else { - valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); @@ -246,14 +248,14 @@ if(options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array // which is the series count and divide by 2 - periodHalfLength = labelAxis.axisLength / data.normalized.length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2; } else if(options.distributeSeries && options.stackBars) { // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis // length by 2 periodHalfLength = labelAxis.axisLength / 2; } else { // On regular bar charts we should just use the series length - periodHalfLength = labelAxis.axisLength / data.normalized[seriesIndex].length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2; } // Adding the series group to the series element @@ -271,7 +273,7 @@ (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - data.normalized[seriesIndex].forEach(function(value, valueIndex) { + data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { var projected, bar, previousStack, @@ -294,13 +296,13 @@ // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex]) } } @@ -349,7 +351,7 @@ positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2); positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); - + var metaData = Chartist.getMetaData(series, valueIndex); // Create bar element diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index 3fbb3d9c..30fc480a 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -69,13 +69,13 @@ showPoint: true, // If the line chart should draw an area showArea: false, - // The base for the area chart that will be used to close the area shape (is normally 0) + // The base for the area chart that will be used to close the area shape (is normally 0) areaBase: 0, // 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. lineSmooth: true, // If the line chart should add a background fill to the .ct-grids group. showGridBackground: false, - // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, @@ -114,11 +114,7 @@ * */ function createChart(options) { - this.data = Chartist.normalizeData(this.data); - var data = { - raw: this.data, - normalized: Chartist.getDataArray(this.data, options.reverseData, true) - }; + var data = Chartist.normalizeData(this.data, options.reverseData, true); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); @@ -131,21 +127,21 @@ var axisX, axisY; if(options.axisX.type === undefined) { - axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { - ticks: data.raw.labels, + axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { + ticks: data.normalized.labels, stretch: options.fullWidth })); } else { - axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX); } if(options.axisY.type === undefined) { - axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high, low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low })); } else { - axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY); } axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); @@ -154,7 +150,7 @@ if (options.showGridBackground) { Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); } - + // Draw the series data.raw.series.forEach(function(series, seriesIndex) { var seriesElement = seriesGroup.elem('g'); @@ -174,10 +170,10 @@ var pathCoordinates = [], pathData = []; - data.normalized[seriesIndex].forEach(function(value, valueIndex) { + data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex]) }; pathCoordinates.push(p.x, p.y); pathData.push({ @@ -241,7 +237,7 @@ this.eventEmitter.emit('draw', { type: 'line', - values: data.normalized[seriesIndex], + values: data.normalized.series[seriesIndex], path: path.clone(), chartRect: chartRect, index: seriesIndex, @@ -295,7 +291,7 @@ // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { type: 'area', - values: data.normalized[seriesIndex], + values: data.normalized.series[seriesIndex], path: areaPath.clone(), series: series, seriesIndex: seriesIndex, diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index aa2384f9..d74cdbde 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -81,15 +81,14 @@ * @param options */ function createChart(options) { - this.data = Chartist.normalizeData(this.data); + var data = Chartist.normalizeData(this.data); var seriesGroups = [], labelsGroup, chartRect, radius, labelRadius, totalDataSum, - startAngle = options.startAngle, - dataArray = Chartist.getDataArray(this.data, options.reverseData); + startAngle = options.startAngle; // Create SVG.js draw this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie); @@ -98,7 +97,7 @@ // Get biggest circle radius possible within chartRect radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { + totalDataSum = options.total || data.normalized.series.reduce(function(previousValue, currentValue) { return previousValue + currentValue; }, 0); @@ -134,7 +133,7 @@ }; // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = this.data.series.filter(function(val) { + var hasSingleValInSeries = data.raw.series.filter(function(val) { return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; @@ -145,11 +144,11 @@ // Draw the series // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { + for (var i = 0; i < data.raw.series.length; i++) { // If current value is zero and we are ignoring empty values then skip to next value - if (dataArray[i] === 0 && options.ignoreEmptyValues) continue; + if (data.normalized.series[i] === 0 && options.ignoreEmptyValues) continue; - var series = this.data.series[i]; + var series = data.raw.series[i]; seriesGroups[i] = this.svg.elem('g', null, null, true); // If the series is an object and contains a name or meta data we add a custom attribute @@ -164,7 +163,7 @@ ].join(' ')); // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. - var endAngle = (totalDataSum > 0 ? startAngle + dataArray[i] / totalDataSum * 360 : 0); + var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[i] / totalDataSum * 360 : 0); // Use slight offset so there are no transparent hairline issues var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); @@ -196,7 +195,7 @@ // Adding the pie series value to the path pathElement.attr({ - 'ct:value': dataArray[i], + 'ct:value': data.normalized.series[i], 'ct:meta': Chartist.serialize(series.meta) }); @@ -210,7 +209,7 @@ // Fire off draw event this.eventEmitter.emit('draw', { type: 'slice', - value: dataArray[i], + value: data.normalized.series[i], totalDataSum: totalDataSum, index: i, meta: series.meta, @@ -227,8 +226,21 @@ // If we need to show labels we need to add the label for this slice now if(options.showLabel) { // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i); + var labelPosition = Chartist.polarToCartesian( + center.x, + center.y, + labelRadius, + startAngle + (endAngle - startAngle) / 2 + ); + + var rawValue; + if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[i])) { + rawValue = data.normalized.labels[i]; + } else { + rawValue = data.normalized.series[i]; + } + + var interpolatedValue = options.labelInterpolationFnc(rawValue, i); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { diff --git a/src/scripts/core.js b/src/scripts/core.js index 681bf2c8..b5688525 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -331,37 +331,46 @@ var Chartist = { * @param {Object} data The data object that is passed as second argument to the charts * @return {Object} The normalized data object */ - Chartist.normalizeData = function(data) { - // Ensure data is present otherwise enforce - data = data || {series: [], labels: []}; - data.series = data.series || []; - data.labels = data.labels || []; + Chartist.normalizeData = function(data, reverse, multi) { + var labelCount; + var output = { + raw: data, + normalized: {} + }; // Check if we should generate some labels based on existing series data - if (data.series.length > 0 && data.labels.length === 0) { - var normalized = Chartist.getDataArray(data), - labelCount; + output.normalized.series = Chartist.getDataArray({ + series: data.series || [] + }, reverse, multi); - // If all elements of the normalized data array are arrays we're dealing with - // data from Bar or Line charts and we need to find the largest series if they are un-even - if (normalized.every(function(value) { + // If all elements of the normalized data array are arrays we're dealing with + // multi series data and we need to find the largest series if they are un-even + if (output.normalized.series.every(function(value) { return value instanceof Array; })) { - // Getting the series with the the most elements - labelCount = Math.max.apply(null, normalized.map(function(series) { - return series.length; - })); - } else { - // We're dealing with Pie data so we just take the normalized array length - labelCount = normalized.length; - } + // Getting the series with the the most elements + labelCount = Math.max.apply(null, output.normalized.series.map(function(series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = output.normalized.series.length; + } - // Setting labels to an array with emptry strings using our labelCount estimated above - data.labels = Chartist.times(labelCount).map(function() { + output.normalized.labels = (data.labels || []).slice(); + // Padding the labels to labelCount with empty strings + Array.prototype.push.apply( + output.normalized.labels, + Chartist.times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() { return ''; - }); + }) + ); + + if(reverse) { + Chartist.reverseData(output.normalized); } - return data; + + return output; }; /** @@ -416,15 +425,7 @@ var Chartist = { * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ - Chartist.getDataArray = function (data, reverse, multi) { - // If the data should be reversed but isn't we need to reverse it - // If it's reversed but it shouldn't we need to reverse it back - // That's required to handle data updates correctly and to reflect the responsive configurations - if(reverse && !data.reversed || !reverse && data.reversed) { - Chartist.reverseData(data); - data.reversed = !data.reversed; - } - + Chartist.getDataArray = function(data, reverse, multi) { // Recursively walks through nested arrays and convert string values to numbers and objects with value properties // to values. Check the tests in data core -> data normalization for a detailed specification of expected values function recursiveConvert(value) { diff --git a/test/spec/spec-axes.js b/test/spec/spec-axes.js index 892b2313..f2556653 100644 --- a/test/spec/spec-axes.js +++ b/test/spec/spec-axes.js @@ -12,11 +12,7 @@ describe('Axes tests', function() { 'rectEnd':'y1', 'rectOffset':'x1' }, - data = { - 'raw': { - 'series':[[1]] - } - }, + data = [[1]], chartRect = { 'y2':0, 'y1':15, @@ -43,12 +39,7 @@ describe('Axes tests', function() { 'rectEnd':'y1', 'rectOffset':'x1' }, - data = { - 'raw': { - 'series':[[ {x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5} ]] - }, - 'normalized':[[ {'y':10,'x':1},{'y':5,'x':2},{'y':-5,'x':3} ]] - }, + data = [[ {x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5} ]], chartRect = { 'padding':{'top':15,'right':15,'bottom':5,'left':10}, 'y2':15, From 4d59882e051e9e4123585ced3b9cfe4ed1e2d6d7 Mon Sep 17 00:00:00 2001 From: Jonathan Dumaine Date: Thu, 15 Sep 2016 16:17:57 -0700 Subject: [PATCH 439/593] Allow bar charts to have auto scaling axis by overriding referenceValue --- src/scripts/charts/bar.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index 701cd11f..d52ec993 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -65,6 +65,8 @@ high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale. + referenceValue: 0, // 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} chartPadding: { top: 15, @@ -136,6 +138,7 @@ var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); if(options.stackBars && data.normalized.series.length !== 0) { + // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { @@ -148,14 +151,13 @@ }, {x: 0, y: 0}); }); - highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, { - referenceValue: 0 - }), options.horizontalBars ? 'x' : 'y'); + highLow = Chartist.getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y'); + } else { - highLow = Chartist.getHighLow(data.normalized.series, Chartist.extend({}, options, { - referenceValue: 0 - }), options.horizontalBars ? 'x' : 'y'); + + highLow = Chartist.getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y'); } + // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); From affc137ec55c77fe355c3b6f1ff085e1782377d9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 22 Oct 2016 11:40:45 +0200 Subject: [PATCH 440/593] Added public getNode on SVG api, fixes #812 --- src/scripts/svg.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/scripts/svg.js b/src/scripts/svg.js index ed87a49c..46719357 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -146,6 +146,16 @@ return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; } + /** + * Returns the underlying SVG node for the current element. + * + * @memberof Chartist.Svg + * @returns {Node} + */ + function getNode() { + return this._node; + } + /** * 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. * @@ -483,6 +493,7 @@ root: root, querySelector: querySelector, querySelectorAll: querySelectorAll, + getNode: getNode, foreignObject: foreignObject, text: text, empty: empty, From 7de3e2c1ea818ae71b1e735d7f57c079a3328f25 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 22 Oct 2016 11:53:21 +0200 Subject: [PATCH 441/593] Added dominant-baseline styles for pie and donut charts, fixes #610 --- src/styles/chartist.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index e4726d8a..e3caaa6b 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -123,6 +123,11 @@ @include ct-flex(); } + .#{$ct-class-chart-pie} .#{$ct-class-label}, + .#{$ct-class-chart-donut} .#{$ct-class-label} { + dominant-baseline: central; + } + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { @include ct-align-justify(flex-end, flex-start); // Fallback for browsers that don't support foreignObjects From 6076b7df0ae30268f40eb720e0ed0bf529b8cc43 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 22 Oct 2016 12:19:01 +0200 Subject: [PATCH 442/593] Changed order or drawing pie and donut slices, fixes #700 --- src/scripts/charts/pie.js | 45 ++++++++++++++++---------------- test/spec/spec-pie-chart.js | 52 ++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index d74cdbde..562fc104 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -137,36 +137,37 @@ return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; + // Creating the series groups + data.raw.series.forEach(function(series, index) { + seriesGroups[index] = this.svg.elem('g', null, null); + }.bind(this)); //if we need to show labels we create the label group now if(options.showLabel) { - labelsGroup = this.svg.elem('g', null, null, true); + labelsGroup = this.svg.elem('g', null, null); } // Draw the series // initialize series groups - for (var i = 0; i < data.raw.series.length; i++) { + data.raw.series.forEach(function(series, index) { // If current value is zero and we are ignoring empty values then skip to next value - if (data.normalized.series[i] === 0 && options.ignoreEmptyValues) continue; - - var series = data.raw.series[i]; - seriesGroups[i] = this.svg.elem('g', null, null, true); + if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; // If the series is an object and contains a name or meta data we add a custom attribute - seriesGroups[i].attr({ + seriesGroups[index].attr({ 'ct:series-name': series.name }); // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ + seriesGroups[index].addClass([ options.classNames.series, - (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(index)) ].join(' ')); // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. - var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[i] / totalDataSum * 360 : 0); + var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0); // Use slight offset so there are no transparent hairline issues - var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); + var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees @@ -189,13 +190,13 @@ // Create the SVG path // If this is a donut chart we add the donut class, otherwise just a regular slice - var pathElement = seriesGroups[i].elem('path', { + var pathElement = seriesGroups[index].elem('path', { d: path.stringify() }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie); // Adding the pie series value to the path pathElement.attr({ - 'ct:value': data.normalized.series[i], + 'ct:value': data.normalized.series[index], 'ct:meta': Chartist.serialize(series.meta) }); @@ -209,12 +210,12 @@ // Fire off draw event this.eventEmitter.emit('draw', { type: 'slice', - value: data.normalized.series[i], + value: data.normalized.series[index], totalDataSum: totalDataSum, - index: i, + index: index, meta: series.meta, series: series, - group: seriesGroups[i], + group: seriesGroups[index], element: pathElement, path: path.clone(), center: center, @@ -234,13 +235,13 @@ ); var rawValue; - if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[i])) { - rawValue = data.normalized.labels[i]; + if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) { + rawValue = data.normalized.labels[index]; } else { - rawValue = data.normalized.series[i]; + rawValue = data.normalized.series[index]; } - var interpolatedValue = options.labelInterpolationFnc(rawValue, i); + var interpolatedValue = options.labelInterpolationFnc(rawValue, index); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { @@ -252,7 +253,7 @@ // Fire off draw event this.eventEmitter.emit('draw', { type: 'label', - index: i, + index: index, group: labelsGroup, element: labelElement, text: '' + interpolatedValue, @@ -265,7 +266,7 @@ // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; - } + }.bind(this)); this.eventEmitter.emit('created', { chartRect: chartRect, diff --git a/test/spec/spec-pie-chart.js b/test/spec/spec-pie-chart.js index e6480589..ac300b35 100644 --- a/test/spec/spec-pie-chart.js +++ b/test/spec/spec-pie-chart.js @@ -71,9 +71,9 @@ describe('Pie chart tests', function() { it('should set value attribute', function(done) { onCreated(function() { var slices = $('.ct-slice-pie'); - expect(slices.eq(2).attr('ct:value')).toBe('5'); + expect(slices.eq(0).attr('ct:value')).toBe('5'); expect(slices.eq(1).attr('ct:value')).toBe('3'); - expect(slices.eq(0).attr('ct:value')).toBe('4'); + expect(slices.eq(2).attr('ct:value')).toBe('4'); done(); }); }); @@ -110,8 +110,8 @@ describe('Pie chart tests', function() { var slice1 = $('.ct-slice-pie').eq(0); var slice2 = $('.ct-slice-pie').eq(1); - expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,0,0,50.\d+,90L50,50Z/); - expect(slice2.attr('d')).toMatch(/^M50,90A40,40,0,0,0,50,10L50,50Z/); + expect(slice1.attr('d')).toMatch(/^M50,90A40,40,0,0,0,50,10L50,50Z/); + expect(slice2.attr('d')).toMatch(/^M50,10A40,40,0,0,0,50.\d+,90L50,50Z/); done(); }); }); @@ -121,7 +121,7 @@ describe('Pie chart tests', function() { series: [1, 2] }; onCreated(function() { - var slice1 = $('.ct-slice-pie').eq(0); + var slice1 = $('.ct-slice-pie').eq(1); expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,1,0/); done(); }, data); @@ -171,7 +171,7 @@ describe('Pie chart tests', function() { options = { width: 100, height: 100, - chartPadding: 0, + chartPadding: 0 }; }); @@ -186,8 +186,8 @@ describe('Pie chart tests', function() { var slice1 = $('.ct-slice-pie').eq(0); var slice2 = $('.ct-slice-pie').eq(1); - expect(slice1.attr('d')).toMatch(/^M49.9\d*,0A50,50,0,1,0,50,0/); - expect(slice2.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/); + expect(slice1.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/); + expect(slice2.attr('d')).toMatch(/^M49.9\d*,0A50,50,0,1,0,50,0/); done(); }); }); @@ -198,8 +198,8 @@ describe('Pie chart tests', function() { var slice1 = $('.ct-slice-pie').eq(0); var slice2 = $('.ct-slice-pie').eq(1); - expect(slice1.attr('d')).toMatch(/^M100,49.97\d*A50,50,0,1,0,100,49.98\d*/); - expect(slice2.attr('d')).toMatch(/^M100,50.1\d*A50,50,0,0,0,100,50/); + expect(slice1.attr('d')).toMatch(/^M100,50.1\d*A50,50,0,0,0,100,50/); + expect(slice2.attr('d')).toMatch(/^M100,49.97\d*A50,50,0,1,0,100,49.98\d*/); done(); }); }); @@ -210,8 +210,8 @@ describe('Pie chart tests', function() { var slice1 = $('.ct-slice-donut').eq(0); var slice2 = $('.ct-slice-donut').eq(1); - expect(slice1.attr('d')).toMatch(/^M49.9\d*,30A20,20,0,1,0,50,30/); - expect(slice2.attr('d')).toMatch(/^M50.\d+,30A20,20,0,0,0,50,30/); + expect(slice1.attr('d')).toMatch(/^M50.\d+,30A20,20,0,0,0,50,30/); + expect(slice2.attr('d')).toMatch(/^M49.9\d*,30A20,20,0,1,0,50,30/); done(); }); }); @@ -244,9 +244,9 @@ describe('Pie chart tests', function() { expect(slices.length).toBe(3); - expect(slices.eq(2).attr('ct:value')).toBe('1'); + expect(slices.eq(0).attr('ct:value')).toBe('1'); expect(slices.eq(1).attr('ct:value')).toBe('2'); - expect(slices.eq(0).attr('ct:value')).toBe('4'); + expect(slices.eq(2).attr('ct:value')).toBe('4'); done(); }); }); @@ -273,13 +273,13 @@ describe('Pie chart tests', function() { expect(slices.length).toBe(3); - expect(slices.eq(2).attr('ct:value')).toBe('0'); - expect(slices.eq(1).attr('ct:value')).toBe('0'); expect(slices.eq(0).attr('ct:value')).toBe('0'); + expect(slices.eq(1).attr('ct:value')).toBe('0'); + expect(slices.eq(2).attr('ct:value')).toBe('0'); - expect(slices.eq(2).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); - expect(slices.eq(1).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); expect(slices.eq(0).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); + expect(slices.eq(1).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); + expect(slices.eq(2).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z'); done(); }); }); @@ -311,10 +311,10 @@ describe('Pie chart tests', function() { expect(slices.length).toBe(4); - expect(slices.eq(3).attr('ct:value')).toBe('1'); - expect(slices.eq(2).attr('ct:value')).toBe('2'); - expect(slices.eq(1).attr('ct:value')).toBe('0'); - expect(slices.eq(0).attr('ct:value')).toBe('4'); + expect(slices.eq(0).attr('ct:value')).toBe('1'); + expect(slices.eq(1).attr('ct:value')).toBe('2'); + expect(slices.eq(2).attr('ct:value')).toBe('0'); + expect(slices.eq(3).attr('ct:value')).toBe('4'); done(); }); }); @@ -352,10 +352,10 @@ describe('Pie chart tests', function() { it('should set value attribute', function(done) { onCreated(function() { var slices = $('.ct-slice-donut'); - expect(slices.eq(3).attr('ct:value')).toBe('20'); - expect(slices.eq(2).attr('ct:value')).toBe('10'); - expect(slices.eq(1).attr('ct:value')).toBe('30'); - expect(slices.eq(0).attr('ct:value')).toBe('40'); + expect(slices.eq(0).attr('ct:value')).toBe('20'); + expect(slices.eq(1).attr('ct:value')).toBe('10'); + expect(slices.eq(2).attr('ct:value')).toBe('30'); + expect(slices.eq(3).attr('ct:value')).toBe('40'); done(); }); }); From 07efd722dc5546ec19f2d9545fb575d2a6d2706e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 22 Oct 2016 12:24:46 +0200 Subject: [PATCH 443/593] Centered position for labels of single series pie / donut charts, fixes #582 --- src/scripts/charts/pie.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 562fc104..6a80cffb 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -226,13 +226,22 @@ // If we need to show labels we need to add the label for this slice now if(options.showLabel) { - // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian( - center.x, - center.y, - labelRadius, - startAngle + (endAngle - startAngle) / 2 - ); + var labelPosition; + if(data.raw.series.length === 1) { + // If we have only 1 series, we can position the label in the center of the pie + labelPosition = { + x: center.x, + y: center.y + }; + } else { + // Position at the labelRadius distance from center and between start and end angle + labelPosition = Chartist.polarToCartesian( + center.x, + center.y, + labelRadius, + startAngle + (endAngle - startAngle) / 2 + ); + } var rawValue; if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) { From 1b32910002d5254227849adbed2ad17b339f757e Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sat, 22 Oct 2016 12:39:45 +0200 Subject: [PATCH 444/593] Fixed step axis issue with axis stretch and series count 0 --- src/scripts/axes/step-axis.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index 8db1a3db..ca91a75e 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -24,8 +24,8 @@ options.ticks, options); - var calc = (options.ticks.length - (options.stretch ? 1 : 0)); - this.stepLength = this.axisLength / (calc === 0 ? 1 : calc); + var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0)); + this.stepLength = this.axisLength / calc; } function projectValue(value, index) { From 1e62358d24fb61970660dbf007e79bc74b08155b Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 17:08:24 +0200 Subject: [PATCH 445/593] Initial commit --- .doclets.yml | 1 + .editorconfig | 21 + .gitattributes | 1 + .gitignore | 4 + .nvmrc | 2 + .travis.yml | 6 + CONTRIBUTING.md | 29 + LICENSE-MIT | 7 + LICENSE-WTFPL | 13 + README.md | 80 + bs-config.js | 103 + dist/chartist.css | 592 +++ dist/chartist.css.map | 1 + dist/chartist.esm.js | 4248 +++++++++++++++++ dist/chartist.esm.js.map | 1 + dist/chartist.min.css | 2 + dist/chartist.min.css.map | 1 + dist/chartist.umd.js | 9 + dist/chartist.umd.js.map | 1 + index.html | 70 + jspm.config.js | 47 + karma.watch.config.js | 27 + package.json | 88 + src/axes/auto-scale-axis.js | 21 + src/axes/axes.js | 4 + src/axes/axis.js | 109 + src/axes/axis.spec.js | 103 + src/axes/fixed-scale-axis.js | 30 + src/axes/fixed-scale-axis.spec.js | 35 + src/axes/step-axis.js | 15 + src/axes/step-axis.spec.js | 27 + src/charts/bar.js | 431 ++ src/charts/base.js | 174 + src/charts/charts.js | 4 + src/charts/line.js | 402 ++ src/charts/pie.js | 359 ++ src/core/core.js | 8 + src/core/creation.js | 233 + src/core/creation.spec.js | 216 + src/core/data.js | 482 ++ src/core/data.spec.js | 357 ++ src/core/extend.js | 26 + src/core/functional.js | 84 + src/core/globals.js | 34 + src/core/lang.js | 114 + src/core/lang.spec.js | 24 + src/core/math.js | 95 + src/core/options-provider.js | 64 + src/event/event-emitter.js | 63 + src/index.js | 11 + src/interpolation/cardinal.js | 111 + src/interpolation/interpolation.js | 5 + src/interpolation/monotone-cubic.js | 134 + src/interpolation/none.js | 51 + src/interpolation/simple.js | 73 + src/interpolation/step.js | 68 + src/styles/chartist.scss | 241 + src/styles/settings/_chartist-settings.scss | 87 + src/svg/svg-list.js | 41 + src/svg/svg-path.js | 358 ++ src/svg/svg.js | 525 ++ src/testing/fixtures.js | 37 + src/testing/jasmine-dom-matchers.js | 35 + .../spec/fixture-with-multiple-elements.html | 1 + .../spec/fixture-with-single-element.html | 1 + src/testing/spec/fixtures.spec.js | 47 + tooling/node/banner.js | 12 + tooling/node/compile-sass.js | 50 + tooling/node/styles-watch.js | 16 + tooling/node/styles.js | 3 + .../system-loaders/version-loader-plugin.js | 3 + yarn.lock | 4118 ++++++++++++++++ 72 files changed, 14896 insertions(+) create mode 100644 .doclets.yml create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .nvmrc create mode 100644 .travis.yml create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE-MIT create mode 100644 LICENSE-WTFPL create mode 100644 README.md create mode 100644 bs-config.js create mode 100644 dist/chartist.css create mode 100644 dist/chartist.css.map create mode 100644 dist/chartist.esm.js create mode 100644 dist/chartist.esm.js.map create mode 100644 dist/chartist.min.css create mode 100644 dist/chartist.min.css.map create mode 100644 dist/chartist.umd.js create mode 100644 dist/chartist.umd.js.map create mode 100644 index.html create mode 100644 jspm.config.js create mode 100644 karma.watch.config.js create mode 100644 package.json create mode 100644 src/axes/auto-scale-axis.js create mode 100644 src/axes/axes.js create mode 100644 src/axes/axis.js create mode 100644 src/axes/axis.spec.js create mode 100644 src/axes/fixed-scale-axis.js create mode 100644 src/axes/fixed-scale-axis.spec.js create mode 100644 src/axes/step-axis.js create mode 100644 src/axes/step-axis.spec.js create mode 100644 src/charts/bar.js create mode 100644 src/charts/base.js create mode 100644 src/charts/charts.js create mode 100644 src/charts/line.js create mode 100644 src/charts/pie.js create mode 100644 src/core/core.js create mode 100644 src/core/creation.js create mode 100644 src/core/creation.spec.js create mode 100644 src/core/data.js create mode 100644 src/core/data.spec.js create mode 100644 src/core/extend.js create mode 100644 src/core/functional.js create mode 100644 src/core/globals.js create mode 100644 src/core/lang.js create mode 100644 src/core/lang.spec.js create mode 100644 src/core/math.js create mode 100644 src/core/options-provider.js create mode 100644 src/event/event-emitter.js create mode 100644 src/index.js create mode 100644 src/interpolation/cardinal.js create mode 100644 src/interpolation/interpolation.js create mode 100644 src/interpolation/monotone-cubic.js create mode 100644 src/interpolation/none.js create mode 100644 src/interpolation/simple.js create mode 100644 src/interpolation/step.js create mode 100644 src/styles/chartist.scss create mode 100644 src/styles/settings/_chartist-settings.scss create mode 100644 src/svg/svg-list.js create mode 100644 src/svg/svg-path.js create mode 100644 src/svg/svg.js create mode 100644 src/testing/fixtures.js create mode 100644 src/testing/jasmine-dom-matchers.js create mode 100644 src/testing/spec/fixture-with-multiple-elements.html create mode 100644 src/testing/spec/fixture-with-single-element.html create mode 100644 src/testing/spec/fixtures.spec.js create mode 100755 tooling/node/banner.js create mode 100644 tooling/node/compile-sass.js create mode 100755 tooling/node/styles-watch.js create mode 100755 tooling/node/styles.js create mode 100644 tooling/system-loaders/version-loader-plugin.js create mode 100644 yarn.lock diff --git a/.doclets.yml b/.doclets.yml new file mode 100644 index 00000000..ea7c2ac6 --- /dev/null +++ b/.doclets.yml @@ -0,0 +1 @@ +dir: src diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..c2cdfb8a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 2 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..21256661 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..673420c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/node_modules +/jspm_packages +npm-debug.log + diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..be628fe2 --- /dev/null +++ b/.nvmrc @@ -0,0 +1,2 @@ +v6.9.0 + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..405a6c49 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - '5.5.0' +before_script: + - 'npm install -g bower grunt-cli' + - 'bower install' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..8119c5e7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,29 @@ +# Contributing to chartist-js + + - [Issues and Bugs](#issue) + - [Submission Guidelines](#submit) + +## Found an Issue? + +If you find a bug in the source code or a mistake in the documentation, you can help us by +submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request +with a fix. + +## Pre-requisites + +You will need the following to run a local development enviroment. + +- Node.js & npm +- Yarn (`npm install yarn -g`) +- Text editor of your choice + + +## How to Run a Local Distribution + +1. `cd` into your local copy of the repository. +2. Run `yarn install` to install dependencies located in `package.json`. +5. Run `yarn start` to start the watch task, and the web server should automatically open. Congrats, you should now be able to see your local copy of the Chartist testbed. + +## Submission Guidelines + +If you are creating a Pull Request, fork the repository and make any changes on the `develop` branch. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..976cde6e --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,7 @@ +Copyright (c) 2013 Gion Kunz + +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: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE-WTFPL b/LICENSE-WTFPL new file mode 100644 index 00000000..5c93f456 --- /dev/null +++ b/LICENSE-WTFPL @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md new file mode 100644 index 00000000..348946be --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# Big welcome by the Chartist Guy + +[![Join the chat at https://gitter.im/gionkunz/chartist-js](https://badges.gitter.im/gionkunz/chartist-js.svg)](https://gitter.im/gionkunz/chartist-js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![npm version](http://img.shields.io/npm/v/chartist.svg)](https://npmjs.org/package/chartist) [![build status](http://img.shields.io/travis/gionkunz/chartist-js.svg)](https://travis-ci.org/gionkunz/chartist-js) [![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) + +![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") + +*Checkout the documentation site at http://gionkunz.github.io/chartist-js/* + +*Checkout this lightning talk that gives you an overview of Chartist in 5 minutes https://www.youtube.com/watch?v=WdYzPhOB_c8* + +*Guest talk of the Chartist.js Guy at the Treehouse Show https://www.youtube.com/watch?v=h9oH0iDaZDQ&t=2m40s* + +Chartist.js is a simple responsive charting library built with SVG. There are hundreds of nice charting libraries already +out there, but they are either: + +* not responsive +* use the wrong technologies for illustration (canvas) +* are not flexible enough while keeping the configuration simple +* are not friendly to your own code +* are not friendly to designers +* have unnecessary dependencies to monolithic libraries +* more annoying things + +That's why we started Chartist.js and our goal is to solve all of the above issues. + +## What is it made for? + +Chartist's goal is to provide a simple, lightweight and unintrusive library to responsively craft charts on your website. +It's important to understand that one of the main intentions of Chartist.js is to rely on standards rather than providing +it's own solution to a problem which is already solved by those standards. We need to leverage the power of browsers +today and say good bye to the idea of solving all problems ourselves. + +Chartist works with inline-SVG and therefore leverages the power of the DOM to provide parts of its functionality. This +also means that Chartist does not provide it's own event handling, labels, behaviors or anything else that can just be +done with plain HTML, JavaScript and CSS. The single and only responsibility of Chartist is to help you drawing "Simple +responsive Charts" using inline-SVG in the DOM, CSS to style and JavaScript to provide an API for configuring your charts. + +## Example site + +You can visit this Site http://gionkunz.github.io/chartist-js/ which is in fact a build of the current project. +We are still developing and constantly add features but you can already use Chartist.js in your projects as we have +reached a stable and reliable state already. + +## Version notes + +We are currently still heavily developing in order to make Chartist.js better. Your help is needed! Please contribute +to the project if you like the idea and the concept and help us to bring nice looking responsive open-source charts +to the masses. + +### Important missing stuff + +1. Jasmine Tests! +2. Documentation: JSDoc, Getting started documentation and landing page +3. Better accessibility using ARIA and other optimizations +4. Better interfaces to the library (i.e. jQuery with data-* attributes for configuration), Angular.js directive etc. +5. Richer Sass / CSS framework +6. Other charts types (spider etc.) + +## Plugins + +Some features aren't right for the core product +but there is a great set of plugins available +which add features like: + +* [Axis labels](http://gionkunz.github.io/chartist-js/plugins.html#axis-title-plugin) +* [Tooltips at data points](https://gionkunz.github.io/chartist-js/plugins.html#tooltip-plugin) +* [Coloring above/below a threshold](https://gionkunz.github.io/chartist-js/plugins.html#threshold-plugin) + +and more. + +See all the plugins [here](https://gionkunz.github.io/chartist-js/plugins.html). + +## Contribution + +We are looking for people who share the idea of having a simple, flexible charting library that is responsive and uses +modern and future-proof technologies. The goal of this project is to create a responsive charting library where developers +have their joy in using it and designers love it because of the designing flexibility they have. + +Contribute if you like the Chartist Guy! diff --git a/bs-config.js b/bs-config.js new file mode 100644 index 00000000..2afd471a --- /dev/null +++ b/bs-config.js @@ -0,0 +1,103 @@ + +/* + |-------------------------------------------------------------------------- + | Browser-sync config file + |-------------------------------------------------------------------------- + | + | For up-to-date information about the options: + | http://www.browsersync.io/docs/options/ + | + | There are more options than you see here, these are just the ones that are + | set internally. See the website for more info. + | + | + */ +module.exports = { + "ui": { + "port": 3001, + "weinre": { + "port": 8080 + } + }, + "files": [ + "dist/**/*.css", "src/**/*.js", "index.html" + ], + "watchOptions": {}, + "server": true, + "proxy": false, + "port": 3000, + "middleware": false, + "serveStatic": [], + "ghostMode": { + "clicks": true, + "scroll": true, + "forms": { + "submit": true, + "inputs": true, + "toggles": true + } + }, + "logLevel": "info", + "logPrefix": "BS", + "logConnections": false, + "logFileChanges": true, + "logSnippet": true, + "rewriteRules": [], + "open": "local", + "browser": "default", + "cors": false, + "xip": false, + "hostnameSuffix": false, + "reloadOnRestart": false, + "notify": true, + "scrollProportionally": true, + "scrollThrottle": 0, + "scrollRestoreTechnique": "window.name", + "scrollElements": [], + "scrollElementMapping": [], + "reloadDelay": 0, + "reloadDebounce": 0, + "reloadThrottle": 0, + "plugins": [], + "injectChanges": true, + "startPath": null, + "minify": true, + "host": null, + "localOnly": false, + "codeSync": true, + "timestamps": true, + "clientEvents": [ + "scroll", + "scroll:element", + "input:text", + "input:toggles", + "form:submit", + "form:reset", + "click" + ], + "socket": { + "socketIoOptions": { + "log": false + }, + "socketIoClientConfig": { + "reconnectionAttempts": 50 + }, + "path": "/browser-sync/socket.io", + "clientPath": "/browser-sync", + "namespace": "/browser-sync", + "clients": { + "heartbeatTimeout": 5000 + } + }, + "tagNames": { + "less": "link", + "scss": "link", + "css": "link", + "jpg": "img", + "jpeg": "img", + "png": "img", + "svg": "img", + "gif": "img", + "js": "script" + } +}; diff --git a/dist/chartist.css b/dist/chartist.css new file mode 100644 index 00000000..f5ff2388 --- /dev/null +++ b/dist/chartist.css @@ -0,0 +1,592 @@ +.ct-label { + fill: rgba(0, 0, 0, 0.4); + color: rgba(0, 0, 0, 0.4); + font-size: 0.75rem; + line-height: 1; } + +.ct-chart-line .ct-label, +.ct-chart-bar .ct-label { + display: block; + display: -webkit-box; + display: -ms-flexbox; + display: flex; } + +.ct-chart-pie .ct-label, +.ct-chart-donut .ct-label { + dominant-baseline: central; } + +.ct-label.ct-horizontal.ct-start { + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end; + -webkit-box-pack: 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; + -ms-flex-align: flex-start; + align-items: flex-start; + -webkit-box-pack: 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; + -ms-flex-align: flex-end; + align-items: flex-end; + -webkit-box-pack: 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; + -ms-flex-align: flex-end; + align-items: flex-end; + -webkit-box-pack: 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; + -ms-flex-align: flex-end; + align-items: flex-end; + -webkit-box-pack: 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; + -ms-flex-align: flex-start; + align-items: flex-start; + -webkit-box-pack: 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; + -ms-flex-align: flex-end; + align-items: flex-end; + -webkit-box-pack: 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; + -ms-flex-align: flex-start; + align-items: flex-start; + -webkit-box-pack: 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; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: 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; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: flex-start; + -ms-flex-pack: flex-start; + justify-content: flex-start; + text-align: left; + text-anchor: end; } + +.ct-grid { + stroke: rgba(0, 0, 0, 0.2); + stroke-width: 1px; + stroke-dasharray: 2px; } + +.ct-grid-background { + fill: none; } + +.ct-point { + stroke-width: 10px; + stroke-linecap: round; } + +.ct-line { + fill: none; + stroke-width: 4px; } + +.ct-area { + stroke: none; + fill-opacity: 0.1; } + +.ct-bar { + fill: none; + stroke-width: 10px; } + +.ct-slice-donut { + fill: none; + stroke-width: 60px; } + +.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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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.88889%; } + .ct-major-second:after { + content: ""; + display: table; + clear: both; } + .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.33333%; } + .ct-minor-third:after { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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.66667%; } + .ct-perfect-fifth:after { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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.8047%; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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.33333%; } + .ct-major-seventh:after { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .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.33333%; } + .ct-major-twelfth:after { + content: ""; + display: table; + clear: both; } + .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 { + content: ""; + display: table; + clear: both; } + .ct-double-octave > svg { + display: block; + position: absolute; + top: 0; + left: 0; } +/*# sourceMappingURL=chartist.css.map */ \ No newline at end of file diff --git a/dist/chartist.css.map b/dist/chartist.css.map new file mode 100644 index 00000000..74426712 --- /dev/null +++ b/dist/chartist.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/styles/chartist.scss","src/styles/settings/_chartist-settings.scss"],"names":[],"mappings":"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","file":"chartist.css"} \ No newline at end of file diff --git a/dist/chartist.esm.js b/dist/chartist.esm.js new file mode 100644 index 00000000..cadb6b24 --- /dev/null +++ b/dist/chartist.esm.js @@ -0,0 +1,4248 @@ +/* Chartist.js 1.0.0 + * Copyright © 2016 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 + */ +var version = '1.0.0'; + +/** + * This object contains all namespaces used within Chartist. + * + * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}} + */ +var 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' +}; + +/** + * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number. + * + * @type {number} + */ +var precision = 8; + +/** + * A map with characters to escape for strings to be safely used as attribute values. + * + * @type {Object} + */ +var escapingMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' +}; + +/** + * Replaces all occurrences of subStr in str with newSubStr and returns a new string. + * + * @param {String} str + * @param {String} subStr + * @param {String} newSubStr + * @return {String} + */ +function replaceAll(str, subStr, newSubStr) { + return str.replace(new RegExp(subStr, 'g'), newSubStr); +} + +/** + * This is a wrapper around document.querySelector that will return the query if it's already of type Node + * + * @memberof Chartist.Core + * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly + * @return {Node} + */ +function querySelector$1(query) { + return query instanceof Node ? query : document.querySelector(query); +} + +/** + * This function safely checks if an objects has an owned property. + * + * @param {Object} object The object where to check for a property + * @param {string} property The property name + * @returns {boolean} Returns true if the object owns the specified property + */ +function safeHasProperty(object, property) { + return object !== null && typeof object === 'object' && object.hasOwnProperty(property); +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param value + * @returns {Boolean} + */ +function isNumeric(value) { + return value === null ? false : isFinite(value); +} + +/** + * Returns true on all falsey values except the numeric value 0. + * + * @memberof Chartist.Core + * @param value + * @returns {boolean} + */ +function isFalseyButZero(value) { + return !value && value !== 0; +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param value + * @returns {*} + */ +function getNumberOrUndefined(value) { + return isNumeric(value) ? +value : undefined; +} + +/** + * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {Number} value + * @param {String} unit + * @return {String} Returns the passed number value with unit. + */ +function ensureUnit(value, unit) { + if (typeof value === 'number') { + value = value + unit; + } + + return value; +} + +/** + * Converts a number or string to a quantity object. + * + * @memberof Chartist.Core + * @param {String|Number} input + * @return {Object} Returns an object containing the value as number and the unit as string. + */ +function quantity(input) { + if (typeof input === 'string') { + var match = /^(\d+)\s*(.*)$/g.exec(input); + return { + value: +match[1], + unit: match[2] || undefined + }; + } + return { value: input }; +} + +/** + * Generates a-z from a number 0 to 26 + * + * @memberof Chartist.Core + * @param {Number} n A number from 0 to 26 that will result in a letter a-z + * @return {String} A character from a-z based on the input number n + */ +function alphaNumerate(n) { + // Limit to a-z + return String.fromCharCode(97 + n % 26); +} + +/** + * Helps to simplify functional style code + * + * @memberof Chartist.Core + * @param {*} n This exact value will be returned by the noop function + * @return {*} The same value that was provided to the n parameter + */ +function noop(n) { + return n; +} + +/** + * Functional style helper to produce array with given length initialized with undefined values + * + * @memberof Chartist.Core + * @param length + * @return {Array} + */ +function times(length) { + return Array.apply(null, new Array(length)); +} + +/** + * Sum helper to be used in reduce functions + * + * @memberof Chartist.Core + * @param previous + * @param current + * @return {*} + */ +function sum(previous, current) { + return previous + (current ? current : 0); +} + +/** + * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor. + * + * @memberof Chartist.Core + * @param {Number} factor + * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array + */ +function mapMultiply(factor) { + return function (num) { + return num * factor; + }; +} + +/** + * Add helper to be used in `Array.map` for adding a addend to each value of an array. + * + * @memberof Chartist.Core + * @param {Number} addend + * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array + */ +function mapAdd(addend) { + return function (num) { + return num + addend; + }; +} + +/** + * 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). + * + * @memberof Chartist.Core + * @param arr + * @param cb + * @return {Array} + */ +function serialMap(arr, cb) { + var result = [], + length = Math.max.apply(null, arr.map(function (e) { + return e.length; + })); + + times(length).forEach(function (e, index) { + var args = arr.map(function (e) { + return e[index]; + }); + + result[index] = cb.apply(null, args); + }); + + return result; +} + +/** + * Calculate the order of magnitude for the chart scale + * + * @memberof Chartist.Core + * @param {Number} value The value Range of the chart + * @return {Number} The order of magnitude + */ +function orderOfMagnitude(value) { + return Math.floor(Math.log(Math.abs(value)) / Math.LN10); +} + +/** + * Project a data length into screen coordinates (pixels) + * + * @memberof Chartist.Core + * @param {Object} axisLength The svg element for the chart + * @param {Number} length Single data value from a series array + * @param {Object} bounds All the values to set the bounds of the chart + * @return {Number} The projected data length in pixels + */ +function projectLength(axisLength, length, bounds) { + return length / bounds.range * axisLength; +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param {Number} value The value that should be rounded with precision + * @param {Number} [digits] The number of digits after decimal used to do the rounding + * @returns {number} Rounded value + */ +function roundWithPrecision(value, digits) { + var precision$$1 = Math.pow(10, digits || precision$$1); + return Math.round(value * precision$$1) / precision$$1; +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param {Number} num An integer number where the smallest factor should be searched for + * @returns {Number} The smallest integer factor of the parameter num. + */ +function rho(num) { + if (num === 1) { + return num; + } + + function gcd(p, q) { + if (p % q === 0) { + return q; + } else { + return gcd(q, p % q); + } + } + + function f(x) { + return x * x + 1; + } + + var x1 = 2, + x2 = 2, + divisor; + if (num % 2 === 0) { + return 2; + } + + do { + x1 = f(x1) % num; + x2 = f(f(x2)) % num; + divisor = gcd(Math.abs(x1 - x2), num); + } while (divisor === 1); + + return divisor; +} + +/** + * Calculate cartesian coordinates of polar coordinates + * + * @memberof Chartist.Core + * @param {Number} centerX X-axis coordinates of center point of circle segment + * @param {Number} centerY X-axis coordinates of center point of circle segment + * @param {Number} radius Radius of circle segment + * @param {Number} angleInDegrees Angle of circle segment in degrees + * @return {{x:Number, y:Number}} Coordinates of point on circumference + */ +function polarToCartesian(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; + + return { + x: centerX + radius * Math.cos(angleInRadians), + y: centerY + radius * Math.sin(angleInRadians) + }; +} + +/** + * Simple recursive object extend + * + * @memberof Chartist.Core + * @param {Object} target Target object where the source will be merged into + * @param {Object...} sources This object (objects) will be merged into target and then target is returned + * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source + */ +function extend(target) { + var i, source, sourceProp; + target = target || {}; + + for (i = 1; i < arguments.length; i++) { + source = arguments[i]; + for (var prop in source) { + sourceProp = source[prop]; + if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { + target[prop] = extend(target[prop], sourceProp); + } else { + target[prop] = sourceProp; + } + } + } + + return target; +} + +/** + * 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. + * If called with null or undefined the function will return immediately with null or undefined. + * + * @memberof Chartist.Core + * @param {Number|String|Object} data + * @return {String} + */ +function serialize(data) { + if (data === null || data === undefined) { + return data; + } else if (typeof data === 'number') { + data = '' + data; + } else if (typeof data === 'object') { + data = JSON.stringify({ data: data }); + } + + return Object.keys(escapingMap).reduce(function (result, key) { + return replaceAll(result, key, escapingMap[key]); + }, data); +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param {String} data + * @return {String|Number|Object} + */ +function deserialize(data) { + if (typeof data !== 'string') { + return data; + } + + data = Object.keys(escapingMap).reduce(function (result, key) { + return replaceAll(result, escapingMap[key], key); + }, data); + + try { + data = JSON.parse(data); + data = data.data !== undefined ? data.data : data; + } catch (e) {} + + return data; +} + +/** + * Ensures that the data object passed as second argument to the charts is present and correctly initialized. + * + * @param {Object} data The data object that is passed as second argument to the charts + * @return {Object} The normalized data object + */ +function normalizeData(data, reverse, multi) { + var labelCount; + var output = { + raw: data, + normalized: {} + }; + + // Check if we should generate some labels based on existing series data + output.normalized.series = getDataArray({ + series: data.series || [] + }, reverse, multi); + + // If all elements of the normalized data array are arrays we're dealing with + // multi series data and we need to find the largest series if they are un-even + if (output.normalized.series.every(function (value) { + return value instanceof Array; + })) { + // Getting the series with the the most elements + labelCount = Math.max.apply(null, output.normalized.series.map(function (series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = output.normalized.series.length; + } + + output.normalized.labels = (data.labels || []).slice(); + // Padding the labels to labelCount with empty strings + Array.prototype.push.apply(output.normalized.labels, times(Math.max(0, labelCount - output.normalized.labels.length)).map(function () { + return ''; + })); + + if (reverse) { + reverseData(output.normalized); + } + + return output; +} + +/** + * Get meta data of a specific value in a series. + * + * @param series + * @param index + * @returns {*} + */ +function getMetaData(series, index) { + var value = series.data ? series.data[index] : series[index]; + return value ? value.meta : undefined; +} + +/** + * Checks if a value is considered a hole in the data series. + * + * @param {*} value + * @returns {boolean} True if the value is considered a data hole + */ +function isDataHoleValue(value) { + return value === null || value === undefined || typeof value === 'number' && isNaN(value); +} + +/** + * Reverses the series, labels and series data arrays. + * + * @memberof Chartist.Core + * @param data + */ +function reverseData(data) { + data.labels.reverse(); + data.series.reverse(); + for (var i = 0; i < data.series.length; i++) { + if (typeof data.series[i] === 'object' && data.series[i].data !== undefined) { + data.series[i].data.reverse(); + } else if (data.series[i] instanceof Array) { + data.series[i].reverse(); + } + } +} + +/** + * Convert data series into plain array + * + * @memberof Chartist.Core + * @param {Object} data The series object that contains the data to be visualized in the chart + * @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. + * @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. + * @return {Array} A plain array that contains the data to be visualized in the chart + */ +function getDataArray(data, reverse, multi) { + // Recursively walks through nested arrays and convert string values to numbers and objects with value properties + // to values. Check the tests in data core -> data normalization for a detailed specification of expected values + function recursiveConvert(value) { + if (safeHasProperty(value, 'value')) { + // We are dealing with value object notation so we need to recurse on value property + return recursiveConvert(value.value); + } else if (safeHasProperty(value, 'data')) { + // We are dealing with series object notation so we need to recurse on data property + return recursiveConvert(value.data); + } else if (value instanceof Array) { + // Data is of type array so we need to recurse on the series + return value.map(recursiveConvert); + } else if (isDataHoleValue(value)) { + // We're dealing with a hole in the data and therefore need to return undefined + // We're also returning undefined for multi value output + return undefined; + } else { + // We need to prepare multi value output (x and y data) + if (multi) { + var multiValue = {}; + + // Single series value arrays are assumed to specify the Y-Axis value + // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] + // If multi is a string then it's assumed that it specified which dimension should be filled as default + if (typeof multi === 'string') { + multiValue[multi] = getNumberOrUndefined(value); + } else { + multiValue.y = getNumberOrUndefined(value); + } + + multiValue.x = value.hasOwnProperty('x') ? getNumberOrUndefined(value.x) : multiValue.x; + multiValue.y = value.hasOwnProperty('y') ? getNumberOrUndefined(value.y) : multiValue.y; + + return multiValue; + } else { + // We can return simple data + return getNumberOrUndefined(value); + } + } + } + + return data.series.map(recursiveConvert); +} + +/** + * Checks if provided value object is multi value (contains x or y properties) + * + * @memberof Chartist.Core + * @param value + */ +function isMultiValue(value) { + return typeof value === 'object' && ('x' in value || 'y' in value); +} + +/** + * 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`. + * + * @memberof Chartist.Core + * @param value + * @param dimension + * @param defaultValue + * @returns {*} + */ +function getMultiValue(value, dimension) { + if (isMultiValue(value)) { + return getNumberOrUndefined(value[dimension || 'y']); + } else { + return getNumberOrUndefined(value); + } +} + +/** + * Helper to read series specific options from options object. It automatically falls back to the global option if + * there is no option in the series options. + * + * @param {Object} series Series object + * @param {Object} options Chartist options object + * @param {string} key The options key that should be used to obtain the options + * @returns {*} + */ +function getSeriesOption(series, options, key) { + if (series.name && options.series && options.series[series.name]) { + var seriesOptions = options.series[series.name]; + return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key]; + } else { + return options[key]; + } +} + +/** + * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates + * valueData property describing the segment. + * + * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any + * points with undefined values are discarded. + * + * **Options** + * The following options are used to determine how segments are formed + * ```javascript + * var options = { + * // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment. + * fillHoles: false, + * // If increasingX is true, the coordinates in all segments have strictly increasing x-values. + * increasingX: false + * }; + * ``` + * + * @memberof Chartist.Core + * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn] + * @param {Array} valueData List of associated point values in the form [v1, v2 .. vn] + * @param {Object} [options] Options set by user + * @return {Array} List of segments, each containing a pathCoordinates and valueData property. + */ +function splitIntoSegments(pathCoordinates, valueData, options) { + var defaultOptions = { + increasingX: false, + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + var segments = []; + var hole = true; + + for (var i = 0; i < pathCoordinates.length; i += 2) { + // If this value is a "hole" we set the hole flag + if (getMultiValue(valueData[i / 2].value) === undefined) { + // if(valueData[i / 2].value === undefined) { + if (!options.fillHoles) { + hole = true; + } + } else { + if (options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i - 2]) { + // X is not increasing, so we need to make sure we start a new segment + hole = true; + } + + // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment + if (hole) { + segments.push({ + pathCoordinates: [], + valueData: [] + }); + // As we have a valid value now, we are not in a "hole" anymore + hole = false; + } + + // Add to the segment pathCoordinates and valueData + segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); + segments[segments.length - 1].valueData.push(valueData[i / 2]); + } + } + + return segments; +} + +/** + * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. + * + * @memberof Chartist.Core + * @param {Array} data The array that contains the data to be visualized in the chart + * @param {Object} options The Object that contains the chart options + * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration + * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. + */ +function getHighLow(data, options, dimension) { + // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred + options = extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {}); + + var highLow = { + high: options.high === undefined ? -Number.MAX_VALUE : +options.high, + low: options.low === undefined ? Number.MAX_VALUE : +options.low + }; + var findHigh = options.high === undefined; + var findLow = options.low === undefined; + + // Function to recursively walk through arrays and find highest and lowest number + function recursiveHighLow(data) { + if (data === undefined) { + return undefined; + } else if (data instanceof Array) { + for (var i = 0; i < data.length; i++) { + recursiveHighLow(data[i]); + } + } else { + var value = dimension ? +data[dimension] : +data; + + if (findHigh && value > highLow.high) { + highLow.high = value; + } + + if (findLow && value < highLow.low) { + highLow.low = value; + } + } + } + + // Start to find highest and lowest number recursively + if (findHigh || findLow) { + recursiveHighLow(data); + } + + // Overrides of high / low based on reference value, it will make sure that the invisible reference value is + // used to generate the chart. This is useful when the chart always needs to contain the position of the + // invisible reference value in the view i.e. for bipolar scales. + if (options.referenceValue || options.referenceValue === 0) { + highLow.high = Math.max(options.referenceValue, highLow.high); + highLow.low = Math.min(options.referenceValue, highLow.low); + } + + // If high and low are the same because of misconfiguration or flat data (only the same value) we need + // to set the high or low to 0 depending on the polarity + if (highLow.high <= highLow.low) { + // If both values are 0 we set high to 1 + if (highLow.low === 0) { + highLow.high = 1; + } else if (highLow.low < 0) { + // If we have the same negative value for the bounds we set bounds.high to 0 + highLow.high = 0; + } else if (highLow.high > 0) { + // If we have the same positive value for the bounds we set bounds.low to 0 + highLow.low = 0; + } else { + // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors + highLow.high = 1; + highLow.low = 0; + } + } + + return highLow; +} + +/** + * Calculate and retrieve all the bounds for the chart and return them in one array + * + * @memberof Chartist.Core + * @param {Number} axisLength The length of the Axis used for + * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. + * @param {Number} scaleMinSpace The minimum projected length a step should result in + * @param {Boolean} onlyInteger + * @return {Object} All the values to set the bounds of the chart + */ +function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { + var i, + optimizationCounter = 0, + newMin, + newMax, + bounds = { + high: highLow.high, + low: highLow.low + }; + + bounds.valueRange = bounds.high - bounds.low; + bounds.oom = orderOfMagnitude(bounds.valueRange); + bounds.step = Math.pow(10, bounds.oom); + bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step; + bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step; + bounds.range = bounds.max - bounds.min; + bounds.numberOfSteps = Math.round(bounds.range / bounds.step); + + // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace + // If we are already below the scaleMinSpace value we will scale up + var length = projectLength(axisLength, bounds.step, bounds); + var scaleUp = length < scaleMinSpace; + var smallestFactor = onlyInteger ? rho(bounds.range) : 0; + + // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1 + if (onlyInteger && projectLength(axisLength, 1, bounds) >= scaleMinSpace) { + bounds.step = 1; + } else if (onlyInteger && smallestFactor < bounds.step && projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) { + // If step 1 was too small, we can try the smallest factor of range + // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor + // is larger than the scaleMinSpace we should go for it. + bounds.step = smallestFactor; + } else { + // Trying to divide or multiply by 2 and find the best step value + while (true) { + if (scaleUp && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { + bounds.step /= 2; + if (onlyInteger && bounds.step % 1 !== 0) { + bounds.step *= 2; + break; + } + } else { + break; + } + + if (optimizationCounter++ > 1000) { + throw new Error('Exceeded maximum number of iterations while optimizing scale step!'); + } + } + } + + var EPSILON = 2.221E-16; + bounds.step = Math.max(bounds.step, EPSILON); + function safeIncrement(value, increment) { + // If increment is too small use *= (1+EPSILON) as a simple nextafter + if (value === (value += increment)) { + value *= 1 + (increment > 0 ? EPSILON : -EPSILON); + } + return value; + } + + // Narrow min and max based on new step + newMin = bounds.min; + newMax = bounds.max; + while (newMin + bounds.step <= bounds.low) { + newMin = safeIncrement(newMin, bounds.step); + } + while (newMax - bounds.step >= bounds.high) { + newMax = safeIncrement(newMax, -bounds.step); + } + bounds.min = newMin; + bounds.max = newMax; + bounds.range = bounds.max - bounds.min; + + var values = []; + for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { + var value = roundWithPrecision(i); + if (value !== values[values.length - 1]) { + values.push(i); + } + } + bounds.values = values; + return bounds; +} + +var _classCallCheck = (function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}); + +var _createClass = (function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +})(); + +/** + * This helper class is to wrap multiple `Svg` elements into a list where you can call the `Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Svg` on multiple elements. + * An instance of this class is also returned by `Svg.querySelectorAll`. + * + * @memberof Svg + * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) + * @constructor + */ +var SvgList = function SvgList(nodeList) { + _classCallCheck(this, SvgList); + + var list = this; + + this.svgElements = []; + for (var i = 0; i < nodeList.length; i++) { + this.svgElements.push(new Svg(nodeList[i])); + } + + // Add delegation methods for Svg + Object.keys(Svg.prototype).filter(function (prototypeProperty) { + return ['constructor', 'parent', 'querySelector', 'querySelectorAll', 'replace', 'append', 'classes', 'height', 'width'].indexOf(prototypeProperty) === -1; + }).forEach(function (prototypeProperty) { + list[prototypeProperty] = function () { + var args = Array.prototype.slice.call(arguments, 0); + list.svgElements.forEach(function (element) { + Svg.prototype[prototypeProperty].apply(element, args); + }); + return list; + }; + }); +}; + +/** + * Svg creates a new SVG object wrapper with a starting element. You can use the wrapper to fluently create sub-elements and modify them. + * + * @memberof Svg + * @constructor + * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Svg + * @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. + * @param {String} className This class or class list will be added to the SVG element + * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child + * @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 + */ +var Svg = function () { + function Svg(name, attributes, className, parent, insertFirst) { + _classCallCheck(this, Svg); + + // If Svg is getting called with an SVG element we just return the wrapper + if (name instanceof Element) { + this._node = name; + } else { + this._node = document.createElementNS(namespaces.svg, name); + + // If this is an SVG element created then custom namespace + if (name === 'svg') { + this.attr({ + 'xmlns:ct': namespaces.ct + }); + } + } + + if (attributes) { + this.attr(attributes); + } + + if (className) { + this.addClass(className); + } + + if (parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); + } + } + } + + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Svg + * @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. + * @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. + * @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. + */ + + + _createClass(Svg, [{ + key: 'attr', + value: function attr(attributes, ns) { + if (typeof attributes === 'string') { + if (ns) { + return this._node.getAttributeNS(ns, attributes); + } else { + return this._node.getAttribute(attributes); + } + } + + Object.keys(attributes).forEach(function (key) { + // If the attribute value is undefined we can skip this one + if (attributes[key] === undefined) { + return; + } + + if (key.indexOf(':') !== -1) { + var namespacedAttribute = key.split(':'); + this._node.setAttributeNS(namespaces[namespacedAttribute[0]], key, attributes[key]); + } else { + this._node.setAttribute(key, attributes[key]); + } + }.bind(this)); + + return this; + } + + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @return {Svg} Returns a Svg wrapper object that can be used to modify the containing SVG data + */ + + }, { + key: 'elem', + value: function elem(name, attributes, className, insertFirst) { + return new Svg(name, attributes, className, this, insertFirst); + } + + /** + * Returns the parent Chartist.SVG wrapper object + * + * @memberof Svg + * @return {Svg} Returns a 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. + */ + + }, { + key: 'parent', + value: function parent() { + return this._node.parentNode instanceof SVGElement ? new Svg(this._node.parentNode) : null; + } + + /** + * This method returns a Svg wrapper around the root SVG element of the current tree. + * + * @memberof Svg + * @return {Svg} The root SVG element wrapped in a Svg element + */ + + }, { + key: 'root', + value: function root() { + var node = this._node; + while (node.nodeName !== 'svg') { + node = node.parentNode; + } + return new Svg(node); + } + + /** + * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Svg wrapper. + * + * @memberof Svg + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @return {Svg} The SVG wrapper for the element found or null if no element was found + */ + + }, { + key: 'querySelector', + value: function querySelector(selector) { + var foundNode = this._node.querySelector(selector); + return foundNode ? new Svg(foundNode) : null; + } + + /** + * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Svg.List wrapper. + * + * @memberof Svg + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @return {SvgList} The SVG wrapper list for the element found or null if no element was found + */ + + }, { + key: 'querySelectorAll', + value: function querySelectorAll(selector) { + var foundNodes = this._node.querySelectorAll(selector); + return foundNodes.length ? new SvgList(foundNodes) : null; + } + + /** + * Returns the underlying SVG node for the current element. + * + * @memberof Svg + * @returns {Node} + */ + + }, { + key: 'getNode', + value: function getNode() { + return this._node; + } + + /** + * 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. + * + * @memberof Svg + * @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 + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @return {Svg} New wrapper object that wraps the foreignObject element + */ + + }, { + key: 'foreignObject', + value: function foreignObject(content, attributes, className, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if (typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; + } + + // Adding namespace to content element + content.setAttribute('xmlns', namespaces.xmlns); + + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = this.elem('foreignObject', attributes, className, insertFirst); + + // Add content to foreignObjectElement + fnObj._node.appendChild(content); + + return fnObj; + } + + /** + * This method adds a new text element to the current Svg wrapper. + * + * @memberof Svg + * @param {String} t The text that should be added to the text element that is created + * @return {Svg} The same wrapper object that was used to add the newly created element + */ + + }, { + key: 'text', + value: function text(t) { + this._node.appendChild(document.createTextNode(t)); + return this; + } + + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Svg + * @return {Svg} The same wrapper object that got emptied + */ + + }, { + key: 'empty', + value: function empty() { + while (this._node.firstChild) { + this._node.removeChild(this._node.firstChild); + } + + return this; + } + + /** + * 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. + * + * @memberof Svg + * @return {Svg} The parent wrapper object of the element that got removed + */ + + }, { + key: 'remove', + value: function remove() { + this._node.parentNode.removeChild(this._node); + return this.parent(); + } + + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Svg + * @param {Svg} newElement The new Svg object that will be used to replace the current wrapper object + * @return {Svg} The wrapper of the new element + */ + + }, { + key: 'replace', + value: function replace(newElement) { + this._node.parentNode.replaceChild(newElement._node, this._node); + return newElement; + } + + /** + * This method will append an element to the current element as a child. + * + * @memberof Svg + * @param {Svg} element The Svg element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @return {Svg} The wrapper of the appended object + */ + + }, { + key: 'append', + value: function append(element, insertFirst) { + if (insertFirst && this._node.firstChild) { + this._node.insertBefore(element._node, this._node.firstChild); + } else { + this._node.appendChild(element._node); + } + + return this; + } + + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Svg + * @return {Array} A list of classes or an empty array if there are no classes on the current element + */ + + }, { + key: 'classes', + value: function classes() { + return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; + } + + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Svg + * @param {String} names A white space separated list of class names + * @return {Svg} The wrapper of the current element + */ + + }, { + key: 'addClass', + value: function addClass(names) { + this._node.setAttribute('class', this.classes().concat(names.trim().split(/\s+/)).filter(function (elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ')); + + return this; + } + + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Svg + * @param {String} names A white space separated list of class names + * @return {Svg} The wrapper of the current element + */ + + }, { + key: 'removeClass', + value: function removeClass(names) { + var removedClasses = names.trim().split(/\s+/); + + this._node.setAttribute('class', this.classes().filter(function (name) { + return removedClasses.indexOf(name) === -1; + }).join(' ')); + + return this; + } + + /** + * Removes all classes from the current element. + * + * @memberof Svg + * @return {Svg} The wrapper of the current element + */ + + }, { + key: 'removeAllClasses', + value: function removeAllClasses() { + this._node.setAttribute('class', ''); + return this; + } + + /** + * Get element height using `getBoundingClientRect` + * + * @memberof Svg + * @return {Number} The elements height in pixels + */ + + }, { + key: 'height', + value: function height() { + return this._node.getBoundingClientRect().height; + } + + /** + * Get element width using `getBoundingClientRect` + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + + }, { + key: 'width', + value: function width() { + return this._node.getBoundingClientRect().width; + } + + /** + * 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 `Svg.Easing` or an array with four numbers specifying a cubic Bézier curve. + * **An animations object could look like this:** + * ```javascript + * element.animate({ + * opacity: { + * dur: 1000, + * from: 0, + * to: 1 + * }, + * x1: { + * dur: '1000ms', + * from: 100, + * to: 200, + * easing: 'easeOutQuart' + * }, + * y1: { + * dur: '2s', + * from: 0, + * to: 100 + * } + * }); + * ``` + * **Automatic unit conversion** + * 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. + * **Guided mode** + * 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 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. + * If guided mode is enabled the following behavior is added: + * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) + * - The animate element will be forced to use `fill="freeze"` + * - 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. + * - After the animation the element attribute value will be set to the `to` value of the animation + * - The animate element is deleted from the DOM + * + * @memberof Svg + * @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. + * @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. + * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. + * @return {Svg} The current element where the animation was added + */ + + }, { + key: 'animate', + value: function animate(animations, guided, eventEmitter) { + if (guided === undefined) { + guided = true; + } + + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + + function createAnimate(animationDefinition, guided) { + var attributeProperties = {}, + animate, + timeout, + animationEasing; + + // Check if an easing is specified in the definition object and delete it from the object as it will not + // be part of the animate element attributes. + if (animationDefinition.easing) { + // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object + animationEasing = animationDefinition.easing instanceof Array ? animationDefinition.easing : easings[animationDefinition.easing]; + delete animationDefinition.easing; + } + + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = ensureUnit(animationDefinition.dur, 'ms'); + + if (animationEasing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = animationEasing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + + // Adding "fill: freeze" if we are in guided mode and set initial attribute values + if (guided) { + animationDefinition.fill = 'freeze'; + // Animated property on our element should already be set to the animation from value in guided mode + attributeProperties[attribute] = animationDefinition.from; + this.attr(attributeProperties); + + // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin + // which needs to be in ms aside + timeout = quantity(animationDefinition.begin || 0).value; + animationDefinition.begin = 'indefinite'; + } + + animate = this.elem('animate', extend({ + attributeName: attribute + }, animationDefinition)); + + if (guided) { + // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout + setTimeout(function () { + // If beginElement fails we set the animated attribute to the end position and remove the animate element + // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in + // the browser. (Currently FF 34 does not support animate elements in foreignObjects) + try { + animate._node.beginElement(); + } catch (err) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this), timeout); + } + + if (eventEmitter) { + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animationDefinition + }); + }.bind(this)); + } + + animate._node.addEventListener('endEvent', function handleEndEvent() { + if (eventEmitter) { + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animationDefinition + }); + } + + if (guided) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this)); + } + + // If current attribute is an array of definition objects we create an animate for each and disable guided mode + if (animations[attribute] instanceof Array) { + animations[attribute].forEach(function (animationDefinition) { + createAnimate.bind(this)(animationDefinition, false); + }.bind(this)); + } else { + createAnimate.bind(this)(animations[attribute], guided); + } + }.bind(this)); + + return this; + } + }]); + + return Svg; +}(); + +/** + * 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. + * + * @memberof Svg + * @param {String} feature The SVG 1.1 feature that should be checked for support. + * @return {Boolean} True of false if the feature is supported or not + */ +function isSupported(feature) { + return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1'); +} + +/** + * This Object contains some standard easing cubic bezier curves. Then can be used with their name in the `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. + * + * @memberof Svg + */ +var easings = { + easeInSine: [0.47, 0, 0.745, 0.715], + easeOutSine: [0.39, 0.575, 0.565, 1], + easeInOutSine: [0.445, 0.05, 0.55, 0.95], + easeInQuad: [0.55, 0.085, 0.68, 0.53], + easeOutQuad: [0.25, 0.46, 0.45, 0.94], + easeInOutQuad: [0.455, 0.03, 0.515, 0.955], + easeInCubic: [0.55, 0.055, 0.675, 0.19], + easeOutCubic: [0.215, 0.61, 0.355, 1], + easeInOutCubic: [0.645, 0.045, 0.355, 1], + easeInQuart: [0.895, 0.03, 0.685, 0.22], + easeOutQuart: [0.165, 0.84, 0.44, 1], + easeInOutQuart: [0.77, 0, 0.175, 1], + easeInQuint: [0.755, 0.05, 0.855, 0.06], + easeOutQuint: [0.23, 1, 0.32, 1], + easeInOutQuint: [0.86, 0, 0.07, 1], + easeInExpo: [0.95, 0.05, 0.795, 0.035], + easeOutExpo: [0.19, 1, 0.22, 1], + easeInOutExpo: [1, 0, 0, 1], + easeInCirc: [0.6, 0.04, 0.98, 0.335], + easeOutCirc: [0.075, 0.82, 0.165, 1], + easeInOutCirc: [0.785, 0.135, 0.15, 0.86], + easeInBack: [0.6, -0.28, 0.735, 0.045], + easeOutBack: [0.175, 0.885, 0.32, 1.275], + easeInOutBack: [0.68, -0.55, 0.265, 1.55] +}; + +/** + * Create or reinitialize the SVG element for the chart + * + * @memberof Chartist.Core + * @param {Node} container The containing DOM Node object that will be used to plant the SVG element + * @param {String} width Set the width of the SVG element. Default is 100% + * @param {String} height Set the height of the SVG element. Default is 100% + * @param {String} className Specify a class to be added to the SVG element + * @return {Object} The created/reinitialized SVG element + */ +function createSvg(container, width, height, className) { + var svg; + + width = width || '100%'; + height = height || '100%'; + + // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it + // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ + Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { + return svg.getAttributeNS(namespaces.xmlns, 'ct'); + }).forEach(function removePreviousElement(svg) { + container.removeChild(svg); + }); + + // Create svg object with width and height or use 100% as default + svg = new Svg('svg').attr({ + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); + + // Add the DOM node to our container + container.appendChild(svg._node); + + return svg; +} + +/** + * Converts a number into a padding object. + * + * @memberof Chartist.Core + * @param {Object|Number} padding + * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed + * @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. + */ +function normalizePadding(padding, fallback) { + fallback = fallback || 0; + + return typeof padding === 'number' ? { + top: padding, + right: padding, + bottom: padding, + left: padding + } : { + top: typeof padding.top === 'number' ? padding.top : fallback, + right: typeof padding.right === 'number' ? padding.right : fallback, + bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback, + left: typeof padding.left === 'number' ? padding.left : fallback + }; +} + +/** + * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used + * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements + */ +function createChartRect(svg, options, fallbackPadding) { + var hasAxis = !!(options.axisX || options.axisY); + var yAxisOffset = hasAxis ? options.axisY.offset : 0; + var xAxisOffset = hasAxis ? options.axisX.offset : 0; + // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 + var width = svg.width() || quantity(options.width).value || 0; + var height = svg.height() || quantity(options.height).value || 0; + var normalizedPadding = normalizePadding(options.chartPadding, fallbackPadding); + + // If settings were to small to cope with offset (legacy) and padding, we'll adjust + width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right); + height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom); + + var chartRect = { + padding: normalizedPadding, + width: function width() { + return this.x2 - this.x1; + }, + height: function height() { + return this.y1 - this.y2; + } + }; + + if (hasAxis) { + if (options.axisX.position === 'start') { + chartRect.y2 = normalizedPadding.top + xAxisOffset; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } else { + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1); + } + + if (options.axisY.position === 'start') { + chartRect.x1 = normalizedPadding.left + yAxisOffset; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1); + } + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } + + return chartRect; +} + +/** + * Creates a grid line based on a projected value. + * + * @memberof Chartist.Core + * @param position + * @param index + * @param axis + * @param offset + * @param length + * @param group + * @param classes + * @param eventEmitter + */ +function createGrid(position, index, axis, offset, length, group, classes, eventEmitter) { + var positionalData = {}; + positionalData[axis.units.pos + '1'] = position; + positionalData[axis.units.pos + '2'] = position; + positionalData[axis.counterUnits.pos + '1'] = offset; + positionalData[axis.counterUnits.pos + '2'] = offset + length; + + var gridElement = group.elem('line', positionalData, classes.join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', extend({ + type: 'grid', + axis: axis, + index: index, + group: group, + element: gridElement + }, positionalData)); +} + +/** + * Creates a grid background rect and emits the draw event. + * + * @memberof Chartist.Core + * @param gridGroup + * @param chartRect + * @param className + * @param eventEmitter + */ +function createGridBackground(gridGroup, chartRect, className, eventEmitter) { + var gridBackground = gridGroup.elem('rect', { + x: chartRect.x1, + y: chartRect.y2, + width: chartRect.width(), + height: chartRect.height() + }, className, true); + + // Event for grid background draw + eventEmitter.emit('draw', { + type: 'gridBackground', + group: gridGroup, + element: gridBackground + }); +} + +/** + * Creates a label based on a projected value and an axis. + * + * @memberof Chartist.Core + * @param position + * @param length + * @param index + * @param labels + * @param axis + * @param axisOffset + * @param labelOffset + * @param group + * @param classes + * @param useForeignObject + * @param eventEmitter + */ +function createLabel(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + var labelElement; + var positionalData = {}; + + positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; + positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; + positionalData[axis.units.len] = length; + positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10); + + 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] + ''; + + labelElement = group.foreignObject(content, extend({ + style: 'overflow: visible;' + }, positionalData)); + } else { + labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]); + } + + eventEmitter.emit('draw', extend({ + type: 'label', + axis: axis, + index: index, + group: group, + element: labelElement, + text: labels[index] + }, positionalData)); +} + +/** + * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches + * + * @memberof Chartist.Core + * @param {Object} options Options set by user + * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart + * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events + * @return {Object} The consolidated options object from the defaults, base and matching responsive options + */ +function optionsProvider(options, responsiveOptions, eventEmitter) { + var baseOptions = extend({}, options), + currentOptions, + mediaQueryListeners = [], + i; + + function updateCurrentOptions(mediaEvent) { + var previousOptions = currentOptions; + currentOptions = extend({}, baseOptions); + + if (responsiveOptions) { + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + if (mql.matches) { + currentOptions = extend(currentOptions, responsiveOptions[i][1]); + } + } + } + + if (eventEmitter && mediaEvent) { + eventEmitter.emit('optionsChanged', { + previousOptions: previousOptions, + currentOptions: currentOptions + }); + } + } + + function removeMediaQueryListeners() { + mediaQueryListeners.forEach(function (mql) { + mql.removeListener(updateCurrentOptions); + }); + } + + if (!window.matchMedia) { + throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; + } else if (responsiveOptions) { + + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + mql.addListener(updateCurrentOptions); + mediaQueryListeners.push(mql); + } + } + // Execute initially without an event argument so we get the correct options + updateCurrentOptions(); + + return { + removeMediaQueryListeners: removeMediaQueryListeners, + getCurrentOptions: function getCurrentOptions() { + return extend({}, currentOptions); + } + }; +} + +var EventEmitter = function () { + function EventEmitter() { + _classCallCheck(this, EventEmitter); + + this.handlers = []; + } + + /** + * Add an event handler for a specific event + * + * @memberof Chartist.Event + * @param {String} event The event name + * @param {Function} handler A event handler function + */ + + + _createClass(EventEmitter, [{ + key: 'addEventHandler', + value: function addEventHandler(event, handler) { + this.handlers[event] = this.handlers[event] || []; + this.handlers[event].push(handler); + } + + /** + * Remove an event handler of a specific event name or remove all event handlers for a specific event. + * + * @memberof Chartist.Event + * @param {String} event The event name where a specific or all handlers should be removed + * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. + */ + + }, { + key: 'removeEventHandler', + value: function removeEventHandler(event, handler) { + // Only do something if there are event handlers with this name existing + if (this.handlers[event]) { + // If handler is set we will look for a specific handler and only remove this + if (handler) { + this.handlers[event].splice(this.handlers[event].indexOf(handler), 1); + if (this.handlers[event].length === 0) { + delete this.handlers[event]; + } + } else { + // If no handler is specified we remove all handlers for this event + delete this.handlers[event]; + } + } + } + + /** + * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. + * + * @memberof Chartist.Event + * @param {String} event The event name that should be triggered + * @param {*} data Arbitrary data that will be passed to the event handler callback functions + */ + + }, { + key: 'emit', + value: function emit(event, data) { + // Only do something if there are event handlers with this name existing + if (this.handlers[event]) { + this.handlers[event].forEach(function (handler) { + handler(data); + }); + } + + // Emit event to star event handlers + if (this.handlers['*']) { + this.handlers['*'].forEach(function (starHandler) { + starHandler(event, data); + }); + } + } + }]); + + return EventEmitter; +}(); + +var BaseChart = function () { + /** + * Constructor of chart base class. + * + * @param query + * @param data + * @param defaultOptions + * @param options + * @param responsiveOptions + * @constructor + */ + function BaseChart(query, data, defaultOptions, options, responsiveOptions) { + _classCallCheck(this, BaseChart); + + this.container = querySelector$1(query); + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; + this.defaultOptions = defaultOptions; + this.options = options; + this.responsiveOptions = responsiveOptions; + this.eventEmitter = new EventEmitter(); + this.supportsForeignObject = isSupported('Extensibility'); + this.supportsAnimations = isSupported('AnimationEventsAttribute'); + this.resizeListener = function resizeListener() { + this.update(); + }.bind(this); + + if (this.container) { + // If chartist was already initialized in this container we are detaching all event listeners first + if (this.container.__chartist__) { + this.container.__chartist__.detach(); + } + + this.container.__chartist__ = this; + } + + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + this.initializeTimeoutId = setTimeout(this.initialize.bind(this), 0); + } + + _createClass(BaseChart, [{ + key: 'createChart', + value: function createChart() { + throw new Error('Base chart type can\'t be instantiated!'); + } + + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container + /** + * Updates the chart which currently does a full reconstruction of the SVG DOM + * + * @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. + * @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. + * @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 + * @memberof Chartist.Base + */ + + }, { + key: 'update', + value: function update(data, options, override) { + if (data) { + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'update', + data: this.data + }); + } + + if (options) { + this.options = extend({}, override ? this.options : this.defaultOptions, options); + + // If chartist was not initialized yet, we just set the options and leave the rest to the initialization + // Otherwise we re-create the optionsProvider at this point + if (!this.initializeTimeoutId) { + this.optionsProvider.removeMediaQueryListeners(); + this.optionsProvider = optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + } + } + + // Only re-created the chart if it has been initialized yet + if (!this.initializeTimeoutId) { + this.createChart(this.optionsProvider.getCurrentOptions()); + } + + // Return a reference to the chart object to chain up calls + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + */ + + }, { + key: 'detach', + value: function detach() { + // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore + // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout + if (!this.initializeTimeoutId) { + window.removeEventListener('resize', this.resizeListener); + this.optionsProvider.removeMediaQueryListeners(); + } else { + window.clearTimeout(this.initializeTimeoutId); + } + + return this; + } + + /** + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. + * + * @memberof Chartist.Base + * @param {String} event Name of the event. Check the examples for supported events. + * @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. + */ + + }, { + key: 'on', + value: function on(event, handler) { + this.eventEmitter.addEventHandler(event, handler); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + * @param {String} event Name of the event for which a handler should be removed + * @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. + */ + + }, { + key: 'off', + value: function off(event, handler) { + this.eventEmitter.removeEventHandler(event, handler); + return this; + } + }, { + key: 'initialize', + value: function initialize() { + // Add window resize listener that re-creates the chart + window.addEventListener('resize', this.resizeListener); + + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + this.optionsProvider = optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + // Register options change listener that will trigger a chart update + this.eventEmitter.addEventHandler('optionsChanged', function () { + this.update(); + }.bind(this)); + + // Before the first chart creation we need to register us with all plugins that are configured + // Initialize all relevant plugins with our chart object and the plugin options specified in the config + if (this.options.plugins) { + this.options.plugins.forEach(function (plugin) { + if (plugin instanceof Array) { + plugin[0](this, plugin[1]); + } else { + plugin(this); + } + }.bind(this)); + } + + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'initial', + data: this.data + }); + + // Create the first chart + this.createChart(this.optionsProvider.getCurrentOptions()); + + // As chart is initialized from the event loop now we can reset our timeout reference + // This is important if the chart gets initialized on the same element twice + this.initializeTimeoutId = undefined; + } + }]); + + return BaseChart; +}(); + +var _possibleConstructorReturn = (function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; +}); + +var _inherits = (function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; +}); + +var axisUnits = { + x: { + pos: 'x', + len: 'width', + dir: 'horizontal', + rectStart: 'x1', + rectEnd: 'x2', + rectOffset: 'y2' + }, + y: { + pos: 'y', + len: 'height', + dir: 'vertical', + rectStart: 'y2', + rectEnd: 'y1', + rectOffset: 'x1' + } +}; + +var Axis = function () { + function Axis() { + _classCallCheck(this, Axis); + } + + _createClass(Axis, [{ + key: 'initialize', + value: function initialize(units, chartRect, ticks, options) { + this.units = units; + this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; + this.options = options; + this.chartRect = chartRect; + this.axisLength = chartRect[this.units.rectEnd] - chartRect[this.units.rectStart]; + this.gridOffset = chartRect[this.units.rectOffset]; + this.ticks = ticks; + } + }, { + key: 'projectValue', + value: function projectValue(value, index, data) { + throw new Error('Base axis can\'t be instantiated!'); + } + }, { + key: 'createGridAndLabels', + value: function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) { + var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; + var projectedValues = this.ticks.map(this.projectValue.bind(this)); + var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); + + projectedValues.forEach(function (projectedValue, index) { + var labelOffset = { + x: 0, + y: 0 + }; + + // TODO: Find better solution for solving this problem + // Calculate how much space we have available for the label + var labelLength; + if (projectedValues[index + 1]) { + // If we still have one label ahead, we can calculate the distance to the next tick / label + labelLength = projectedValues[index + 1] - projectedValue; + } else { + // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to + // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will + // still be visible inside of the chart padding. + labelLength = Math.max(this.axisLength - projectedValue, 30); + } + + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + if (isFalseyButZero(labelValues[index]) && labelValues[index] !== '') { + return; + } + + // Transform to global coordinates using the chartRect + // We also need to set the label offset for the createLabel function + if (this.units.pos === 'x') { + projectedValue = this.chartRect.x1 + projectedValue; + labelOffset.x = chartOptions.axisX.labelOffset.x; + + // If the labels should be positioned in start position (top side for vertical axis) we need to set a + // different offset as for positioned with end (bottom) + if (chartOptions.axisX.position === 'start') { + labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } else { + labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } + } else { + projectedValue = this.chartRect.y1 - projectedValue; + labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0); + + // If the labels should be positioned in start position (left side for horizontal axis) we need to set a + // different offset as for positioned with end (right side) + if (chartOptions.axisY.position === 'start') { + labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10; + } else { + labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; + } + } + + if (axisOptions.showGrid) { + createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [chartOptions.classNames.grid, chartOptions.classNames[this.units.dir]], eventEmitter); + } + + if (axisOptions.showLabel) { + createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [chartOptions.classNames.label, chartOptions.classNames[this.units.dir], axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']], useForeignObject, eventEmitter); + } + }.bind(this)); + } + }]); + + return Axis; +}(); + +var _get = (function get(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; + } + + return getter.call(receiver); + } +}); + +var AutoScaleAxis = function (_Axis) { + _inherits(AutoScaleAxis, _Axis); + + function AutoScaleAxis(axisUnit, data, chartRect, options) { + _classCallCheck(this, AutoScaleAxis); + + // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options + var _this = _possibleConstructorReturn(this, (AutoScaleAxis.__proto__ || Object.getPrototypeOf(AutoScaleAxis)).call(this)); + + var highLow = options.highLow || getHighLow(data, options, axisUnit.pos); + _this.bounds = getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); + _this.range = { + min: _this.bounds.min, + max: _this.bounds.max + }; + + _get(AutoScaleAxis.prototype.__proto__ || Object.getPrototypeOf(AutoScaleAxis.prototype), 'initialize', _this).call(_this, axisUnit, chartRect, _this.bounds.values, options); + return _this; + } + + _createClass(AutoScaleAxis, [{ + key: 'projectValue', + value: function projectValue(value) { + return this.axisLength * (+getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; + } + }]); + + return AutoScaleAxis; +}(Axis); + +var FixedScaleAxis = function (_Axis) { + _inherits(FixedScaleAxis, _Axis); + + function FixedScaleAxis(axisUnit, data, chartRect, options) { + _classCallCheck(this, FixedScaleAxis); + + var _this = _possibleConstructorReturn(this, (FixedScaleAxis.__proto__ || Object.getPrototypeOf(FixedScaleAxis)).call(this)); + + var highLow = options.highLow || getHighLow(data, options, axisUnit.pos); + _this.divisor = options.divisor || 1; + _this.ticks = options.ticks || times(_this.divisor).map(function (value, index) { + return highLow.low + (highLow.high - highLow.low) / this.divisor * index; + }.bind(_this)); + _this.ticks.sort(function (a, b) { + return a - b; + }); + _this.range = { + min: highLow.low, + max: highLow.high + }; + + _get(FixedScaleAxis.prototype.__proto__ || Object.getPrototypeOf(FixedScaleAxis.prototype), 'initialize', _this).call(_this, axisUnit, chartRect, _this.ticks, options); + + _this.stepLength = _this.axisLength / _this.divisor; + return _this; + } + + _createClass(FixedScaleAxis, [{ + key: 'projectValue', + value: function projectValue(value) { + return this.axisLength * (+getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); + } + }]); + + return FixedScaleAxis; +}(Axis); + +var StepAxis = function (_Axis) { + _inherits(StepAxis, _Axis); + + function StepAxis(axisUnit, data, chartRect, options) { + _classCallCheck(this, StepAxis); + + var _this = _possibleConstructorReturn(this, (StepAxis.__proto__ || Object.getPrototypeOf(StepAxis)).call(this)); + + _get(StepAxis.prototype.__proto__ || Object.getPrototypeOf(StepAxis.prototype), 'initialize', _this).call(_this, axisUnit, chartRect, options.ticks, options); + + var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0)); + _this.stepLength = _this.axisLength / calc; + return _this; + } + + _createClass(StepAxis, [{ + key: 'projectValue', + value: function projectValue(value, index) { + return this.stepLength * index; + } + }]); + + return StepAxis; +}(Axis); + +/** + * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported. + * + * @memberof SvgPath + * @type {Object} + */ +var elementDescriptions = { + m: ['x', 'y'], + l: ['x', 'y'], + c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'], + a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y'] +}; + +/** + * Default options for newly created SVG path objects. + * + * @memberof SvgPath + * @type {Object} + */ +var defaultOptions$1 = { + // 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. + accuracy: 3 +}; + +function element(command, params, pathElements, pos, relative, data) { + var pathElement = extend({ + command: relative ? command.toLowerCase() : command.toUpperCase() + }, params, data ? { data: data } : {}); + + pathElements.splice(pos, 0, pathElement); +} + +function forEachParam(pathElements, cb) { + pathElements.forEach(function (pathElement, pathElementIndex) { + elementDescriptions[pathElement.command.toLowerCase()].forEach(function (paramName, paramIndex) { + cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + }); + }); +} + +/** + * Used to construct a new path object. + * + * @memberof SvgPath + * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end) + * @param {Object} options Options object that overrides the default objects. See default options for more details. + * @constructor + */ +var SvgPath = function () { + _createClass(SvgPath, null, [{ + key: 'join', + + /** + * This static function on `SvgPath` is joining multiple paths together into one paths. + * + * @memberof SvgPath + * @param {Array} paths A list of paths to be joined together. The order is important. + * @param {boolean} [close] If the newly created path should be a closed path + * @param {Object} [options] Path options for the newly created path. + * @return {SvgPath} + */ + value: function join(paths, close, options) { + var joinedPath = new SvgPath(close, options); + for (var i = 0; i < paths.length; i++) { + var path = paths[i]; + for (var j = 0; j < path.pathElements.length; j++) { + joinedPath.pathElements.push(path.pathElements[j]); + } + } + return joinedPath; + } + }]); + + function SvgPath(close, options) { + _classCallCheck(this, SvgPath); + + this.pathElements = []; + this.pos = 0; + this.close = close; + this.options = extend({}, defaultOptions$1, options); + } + + /** + * 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. + * + * @memberof SvgPath + * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array. + * @return {SvgPath|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. + */ + + + _createClass(SvgPath, [{ + key: 'position', + value: function position(pos) { + if (pos !== undefined) { + this.pos = Math.max(0, Math.min(this.pathElements.length, pos)); + return this; + } else { + return this.pos; + } + } + + /** + * Removes elements from the path starting at the current position. + * + * @memberof SvgPath + * @param {Number} count Number of path elements that should be removed from the current position. + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'remove', + value: function remove(count) { + this.pathElements.splice(this.pos, count); + return this; + } + + /** + * Use this function to add a new move SVG path element. + * + * @memberof SvgPath + * @param {Number} x The x coordinate for the move element. + * @param {Number} y The y coordinate for the move element. + * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'move', + value: function move(x, y, relative, data) { + element('M', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * Use this function to add a new line SVG path element. + * + * @memberof SvgPath + * @param {Number} x The x coordinate for the line element. + * @param {Number} y The y coordinate for the line element. + * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'line', + value: function line(x, y, relative, data) { + element('L', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * Use this function to add a new curve SVG path element. + * + * @memberof SvgPath + * @param {Number} x1 The x coordinate for the first control point of the bezier curve. + * @param {Number} y1 The y coordinate for the first control point of the bezier curve. + * @param {Number} x2 The x coordinate for the second control point of the bezier curve. + * @param {Number} y2 The y coordinate for the second control point of the bezier curve. + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'curve', + value: function curve(x1, y1, x2, y2, x, y, relative, data) { + element('C', { + x1: +x1, + y1: +y1, + x2: +x2, + y2: +y2, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * Use this function to add a new non-bezier curve SVG path element. + * + * @memberof SvgPath + * @param {Number} rx The radius to be used for the x-axis of the arc. + * @param {Number} ry The radius to be used for the y-axis of the arc. + * @param {Number} xAr Defines the orientation of the arc + * @param {Number} lAf Large arc flag + * @param {Number} sf Sweep flag + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'arc', + value: function arc(rx, ry, xAr, lAf, sf, x, y, relative, data) { + element('A', { + rx: +rx, + ry: +ry, + xAr: +xAr, + lAf: +lAf, + sf: +sf, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * 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. + * + * @memberof SvgPath + * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components. + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'parse', + value: function parse(path) { + // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] + var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2').replace(/([0-9])([A-Za-z])/g, '$1 $2').split(/[\s,]+/).reduce(function (result, element) { + if (element.match(/[A-Za-z]/)) { + result.push([]); + } + + result[result.length - 1].push(element); + return result; + }, []); + + // If this is a closed path we remove the Z at the end because this is determined by the close option + if (chunks[chunks.length - 1][0].toUpperCase() === 'Z') { + chunks.pop(); + } + + // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters + // For example {command: 'M', x: '10', y: '10'} + var elements = chunks.map(function (chunk) { + var command = chunk.shift(), + description = elementDescriptions[command.toLowerCase()]; + + return extend({ + command: command + }, description.reduce(function (result, paramName, index) { + result[paramName] = +chunk[index]; + return result; + }, {})); + }); + + // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position + var spliceArgs = [this.pos, 0]; + Array.prototype.push.apply(spliceArgs, elements); + Array.prototype.splice.apply(this.pathElements, spliceArgs); + // Increase the internal position by the element count + this.pos += elements.length; + + return this; + } + + /** + * 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. + * + * @memberof SvgPath + * @return {String} + */ + + }, { + key: 'stringify', + value: function stringify() { + var accuracyMultiplier = Math.pow(10, this.options.accuracy); + + return this.pathElements.reduce(function (path, pathElement) { + var params = elementDescriptions[pathElement.command.toLowerCase()].map(function (paramName) { + return this.options.accuracy ? Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier : pathElement[paramName]; + }.bind(this)); + + return path + pathElement.command + params.join(','); + }.bind(this), '') + (this.close ? 'Z' : ''); + } + + /** + * 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. + * + * @memberof SvgPath + * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements. + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'scale', + value: function scale(x, y) { + forEachParam(this.pathElements, function (pathElement, paramName) { + pathElement[paramName] *= paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * + * @memberof SvgPath + * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements. + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'translate', + value: function translate(x, y) { + forEachParam(this.pathElements, function (pathElement, paramName) { + pathElement[paramName] += paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * The method signature of the callback function looks like this: + * ```javascript + * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) + * ``` + * 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. + * + * @memberof SvgPath + * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description. + * @return {SvgPath} The current path object for easy call chaining. + */ + + }, { + key: 'transform', + value: function transform(transformFnc) { + forEachParam(this.pathElements, function (pathElement, paramName, pathElementIndex, paramIndex, pathElements) { + var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + if (transformed || transformed === 0) { + pathElement[paramName] = transformed; + } + }); + return this; + } + + /** + * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. + * + * @memberof SvgPath + * @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. + * @return {SvgPath} + */ + + }, { + key: 'clone', + value: function clone(close) { + var c = new SvgPath(close || this.close); + c.pos = this.pos; + c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { + return extend({}, pathElement); + }); + c.options = extend({}, this.options); + return c; + } + + /** + * 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. + * + * @memberof SvgPath + * @param {String} command The command you'd like to use to split the path + * @return {Array} + */ + + }, { + key: 'splitByCommand', + value: function splitByCommand(command) { + var split = [new SvgPath()]; + + this.pathElements.forEach(function (pathElement) { + if (pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) { + split.push(new SvgPath()); + } + + split[split.length - 1].pathElements.push(pathElement); + }); + + return split; + } + }]); + + return SvgPath; +}(); + +/** + * This interpolation function does not smooth the path and the result is only containing lines and no curves. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.none({ + * fillHoles: false + * }) + * }); + * + * + * @memberof Chartist.Interpolation + * @return {Function} + */ +function none(options) { + var defaultOptions = { + fillHoles: false + }; + options = extend({}, defaultOptions, options); + return function none(pathCoordinates, valueData) { + var path = new SvgPath(); + var hole = true; + + for (var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var currData = valueData[i / 2]; + + if (getMultiValue(currData.value) !== undefined) { + + if (hole) { + path.move(currX, currY, false, currData); + } else { + path.line(currX, currY, false, currData); + } + + hole = false; + } else if (!options.fillHoles) { + hole = true; + } + } + + return path; + }; +} + +/** + * 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. + * + * 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. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.simple({ + * divisor: 2, + * fillHoles: false + * }) + * }); + * + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the simple interpolation factory function. + * @return {Function} + */ +function simple(options) { + var defaultOptions = { + divisor: 2, + fillHoles: false + }; + options = extend({}, defaultOptions, options); + + var d = 1 / Math.max(1, options.divisor); + + return function simple(pathCoordinates, valueData) { + var path = new SvgPath(); + var prevX, prevY, prevData; + + for (var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var length = (currX - prevX) * d; + var currData = valueData[i / 2]; + + if (currData.value !== undefined) { + + if (prevData === undefined) { + path.move(currX, currY, false, currData); + } else { + path.curve(prevX + length, prevY, currX - length, currY, currX, currY, false, currData); + } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if (!options.fillHoles) { + prevX = currX = prevData = undefined; + } + } + + return path; + }; +} + +/** + * 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. + * + * 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`. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.step({ + * postpone: true, + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param options + * @returns {Function} + */ +function step(options) { + var defaultOptions = { + postpone: true, + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + return function step(pathCoordinates, valueData) { + var path = new SvgPath(); + + var prevX, prevY, prevData; + + for (var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var currData = valueData[i / 2]; + + // If the current point is also not a hole we can draw the step lines + if (currData.value !== undefined) { + if (prevData === undefined) { + path.move(currX, currY, false, currData); + } else { + if (options.postpone) { + // If postponed we should draw the step line with the value of the previous value + path.line(currX, prevY, false, prevData); + } else { + // If not postponed we should draw the step line with the value of the current value + path.line(prevX, currY, false, currData); + } + // Line to the actual point (this should only be a Y-Axis movement + path.line(currX, currY, false, currData); + } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if (!options.fillHoles) { + prevX = prevY = prevData = undefined; + } + } + + return path; + }; +} + +/** + * 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. + * + * 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`. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 1, + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the cardinal factory function. + * @return {Function} + */ +function cardinal(options) { + var defaultOptions = { + tension: 1, + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + var t = Math.min(1, Math.max(0, options.tension)), + c = 1 - t; + + return function cardinal(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles + }); + + if (!segments.length) { + // If there were no segments return 'none' interpolation + return none()([]); + } else if (segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; + // For each segment we will recurse the cardinal function + segments.forEach(function (segment) { + paths.push(cardinal(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return SvgPath.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; + + // If less than two points we need to fallback to no smoothing + if (pathCoordinates.length <= 4) { + return none()(pathCoordinates, valueData); + } + + var path = new SvgPath().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), + z; + + for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { + var p = [{ x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1] }, { x: +pathCoordinates[i], y: +pathCoordinates[i + 1] }, { x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3] }, { x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5] }]; + if (z) { + if (!i) { + p[0] = { x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1] }; + } else if (iLen - 4 === i) { + p[3] = { x: +pathCoordinates[0], y: +pathCoordinates[1] }; + } else if (iLen - 2 === i) { + p[2] = { x: +pathCoordinates[0], y: +pathCoordinates[1] }; + p[3] = { x: +pathCoordinates[2], y: +pathCoordinates[3] }; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = { x: +pathCoordinates[i], y: +pathCoordinates[i + 1] }; + } + } + + path.curve(t * (-p[0].x + 6 * p[1].x + p[2].x) / 6 + c * p[2].x, t * (-p[0].y + 6 * p[1].y + p[2].y) / 6 + c * p[2].y, t * (p[1].x + 6 * p[2].x - p[3].x) / 6 + c * p[2].x, t * (p[1].y + 6 * p[2].y - p[3].y) / 6 + c * p[2].y, p[2].x, p[2].y, false, valueData[(i + 2) / 2]); + } + + return path; + } + }; +} + +/** + * 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. + * + * 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`. + * + * 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. + * + * All smoothing functions within Chartist are factory functions that accept an options parameter. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.monotoneCubic({ + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} [options] The options of the monotoneCubic factory function. + * @return {Function} + */ +function monotoneCubic(options) { + var defaultOptions = { + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + return function monotoneCubic(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles, + increasingX: true + }); + + if (!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return none()([]); + } else if (segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; + // For each segment we will recurse the monotoneCubic fn function + segments.forEach(function (segment) { + paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return SvgPath.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; + + // If less than three points we need to fallback to no smoothing + if (pathCoordinates.length <= 4) { + return none()(pathCoordinates, valueData); + } + + var xs = [], + ys = [], + i, + n = pathCoordinates.length / 2, + ms = [], + ds = [], + dys = [], + dxs = [], + path; + + // Populate x and y coordinates into separate arrays, for readability + + for (i = 0; i < n; i++) { + xs[i] = pathCoordinates[i * 2]; + ys[i] = pathCoordinates[i * 2 + 1]; + } + + // Calculate deltas and derivative + + for (i = 0; i < n - 1; i++) { + dys[i] = ys[i + 1] - ys[i]; + dxs[i] = xs[i + 1] - xs[i]; + ds[i] = dys[i] / dxs[i]; + } + + // Determine desired slope (m) at each point using Fritsch-Carlson method + // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation + + ms[0] = ds[0]; + ms[n - 1] = ds[n - 2]; + + for (i = 1; i < n - 1; i++) { + if (ds[i] === 0 || ds[i - 1] === 0 || ds[i - 1] > 0 !== ds[i] > 0) { + ms[i] = 0; + } else { + ms[i] = 3 * (dxs[i - 1] + dxs[i]) / ((2 * dxs[i] + dxs[i - 1]) / ds[i - 1] + (dxs[i] + 2 * dxs[i - 1]) / ds[i]); + + if (!isFinite(ms[i])) { + ms[i] = 0; + } + } + } + + // Now build a path from the slopes + + path = new SvgPath().move(xs[0], ys[0], false, valueData[0]); + + for (i = 0; i < n - 1; i++) { + path.curve( + // First control point + xs[i] + dxs[i] / 3, ys[i] + ms[i] * dxs[i] / 3, + // Second control point + xs[i + 1] - dxs[i] / 3, ys[i + 1] - ms[i + 1] * dxs[i] / 3, + // End point + xs[i + 1], ys[i + 1], false, valueData[i + 1]); + } + + return path; + } + }; +} + + + +var interpolation = Object.freeze({ + none: none, + simple: simple, + step: step, + cardinal: cardinal, + monotoneCubic: monotoneCubic +}); + +/** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Line + */ +var defaultOptions = { + // Options for X-Axis + axisX: { + // The offset of the labels to the chart area + offset: 30, + // 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. + position: 'end', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // 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. + type: undefined + }, + // Options for Y-Axis + axisY: { + // The offset of the labels to the chart area + offset: 40, + // 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. + position: 'start', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // 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. + type: undefined, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false + }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // If the line should be drawn or not + showLine: true, + // If dots should be drawn or not + showPoint: true, + // If the line chart should draw an area + showArea: false, + // The base for the area chart that will be used to close the area shape (is normally 0) + areaBase: 0, + // 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. + lineSmooth: true, + // If the line chart should add a background fill to the .ct-grids group. + showGridBackground: false, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + low: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + high: undefined, + // 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} + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, + // 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. + fullWidth: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // Override the class names that get used to generate the SVG structure of the chart + 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' + } +}; + +var LineChart = function (_BaseChart) { + _inherits(LineChart, _BaseChart); + + /** + * This method creates a new line chart. + * + * @memberof Chartist.Line + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // Create a simple line chart + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // As options we currently only set a static size of 300x200 px + * var options = { + * width: '300px', + * height: '200px' + * }; + * + * // 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 + * new Chartist.Line('.ct-chart', data, options); + * + * @example + * // Use specific interpolation function with configuration from the Chartist.Interpolation module + * + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [ + * [1, 1, 8, 1, 7] + * ] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 0.2 + * }) + * }); + * + * @example + * // Create a line chart with responsive options + * + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. + * var responsiveOptions = [ + * ['screen and (min-width: 641px) and (max-width: 1024px)', { + * showPoint: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return Mon, Tue, Wed etc. on medium screens + * return value.slice(0, 3); + * } + * } + * }], + * ['screen and (max-width: 640px)', { + * showLine: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return M, T, W etc. on small screens + * return value[0]; + * } + * } + * }] + * ]; + * + * new Chartist.Line('.ct-chart', data, null, responsiveOptions); + * + */ + function LineChart(query, data, options, responsiveOptions) { + _classCallCheck(this, LineChart); + + return _possibleConstructorReturn(this, (LineChart.__proto__ || Object.getPrototypeOf(LineChart)).call(this, query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions)); + } + + /** + * Creates a new chart + * + */ + + + _createClass(LineChart, [{ + key: 'createChart', + value: function createChart(options) { + var data = normalizeData(this.data, options.reverseData, true); + + // Create new svg object + this.svg = createSvg(this.container, options.width, options.height, options.classNames.chart); + // Create groups for labels, grid and series + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + + var chartRect = createChartRect(this.svg, options, defaultOptions.padding); + var axisX, axisY; + + if (options.axisX.type === undefined) { + axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { + ticks: data.normalized.labels, + stretch: options.fullWidth + })); + } else { + axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX); + } + + if (options.axisY.type === undefined) { + axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { + high: isNumeric(options.high) ? options.high : options.axisY.high, + low: isNumeric(options.low) ? options.low : options.axisY.low + })); + } else { + axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, options.axisY); + } + + axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + + if (options.showGridBackground) { + createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + + // Draw the series + data.raw.series.forEach(function (series, seriesIndex) { + var seriesElement = seriesGroup.elem('g'); + + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesElement.attr({ + 'ct:series-name': series.name, + 'ct:meta': serialize(series.meta) + }); + + // Use series class from series data or if not set generate one + seriesElement.addClass([options.classNames.series, series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)].join(' ')); + + var pathCoordinates = [], + pathData = []; + + data.normalized.series[seriesIndex].forEach(function (value, valueIndex) { + var p = { + x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex]) + }; + pathCoordinates.push(p.x, p.y); + pathData.push({ + value: value, + valueIndex: valueIndex, + meta: getMetaData(series, valueIndex) + }); + }.bind(this)); + + var seriesOptions = { + lineSmooth: getSeriesOption(series, options, 'lineSmooth'), + showPoint: getSeriesOption(series, options, 'showPoint'), + showLine: getSeriesOption(series, options, 'showLine'), + showArea: getSeriesOption(series, options, 'showArea'), + areaBase: getSeriesOption(series, options, 'areaBase') + }; + + var smoothing = typeof seriesOptions.lineSmooth === 'function' ? seriesOptions.lineSmooth : seriesOptions.lineSmooth ? monotoneCubic() : none(); + // Interpolating path where pathData will be used to annotate each path element so we can trace back the original + // index, value and meta data + var path = smoothing(pathCoordinates, pathData); + + // If we should show points we need to create them now to avoid secondary loop + // Points are drawn from the pathElements returned by the interpolation function + // Small offset for Firefox to render squares correctly + if (seriesOptions.showPoint) { + + path.pathElements.forEach(function (pathElement) { + var point = seriesElement.elem('line', { + x1: pathElement.x, + y1: pathElement.y, + x2: pathElement.x + 0.01, + y2: pathElement.y + }, options.classNames.point).attr({ + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(isNumeric).join(','), + 'ct:meta': serialize(pathElement.data.meta) + }); + + this.eventEmitter.emit('draw', { + type: 'point', + value: pathElement.data.value, + index: pathElement.data.valueIndex, + meta: pathElement.data.meta, + series: series, + seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, + group: seriesElement, + element: point, + x: pathElement.x, + y: pathElement.y + }); + }.bind(this)); + } + + if (seriesOptions.showLine) { + var line = seriesElement.elem('path', { + d: path.stringify() + }, options.classNames.line, true); + + this.eventEmitter.emit('draw', { + type: 'line', + values: data.normalized.series[seriesIndex], + path: path.clone(), + chartRect: chartRect, + index: seriesIndex, + series: series, + seriesIndex: seriesIndex, + seriesMeta: series.meta, + axisX: axisX, + axisY: axisY, + group: seriesElement, + element: line + }); + } + + // Area currently only works with axes that support a range! + if (seriesOptions.showArea && axisY.range) { + // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); + + // In order to form the area we'll first split the path by move commands so we can chunk it up into segments + path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { + // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area + return pathSegment.pathElements.length > 1; + }).map(function convertToArea(solidPathSegments) { + // Receiving the filtered solid path segments we can now convert those segments into fill areas + var firstElement = solidPathSegments.pathElements[0]; + var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; + + // Cloning the solid path segment with closing option and removing the first move command from the clone + // We then insert a new move that should start at the area base and draw a straight line up or down + // at the end of the path we add an additional straight line to the projected area base value + // As the closing option is set our path will be automatically closed + return solidPathSegments.clone(true).position(0).remove(1).move(firstElement.x, areaBaseProjected).line(firstElement.x, firstElement.y).position(solidPathSegments.pathElements.length + 1).line(lastElement.x, areaBaseProjected); + }).forEach(function createArea(areaPath) { + // For each of our newly created area paths, we'll now create path elements by stringifying our path objects + // and adding the created DOM elements to the correct series group + var area = seriesElement.elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true); + + // Emit an event for each area that was drawn + this.eventEmitter.emit('draw', { + type: 'area', + values: data.normalized.series[seriesIndex], + path: areaPath.clone(), + series: series, + seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, + chartRect: chartRect, + index: seriesIndex, + group: seriesElement, + element: area + }); + }.bind(this)); + } + }.bind(this)); + + this.eventEmitter.emit('created', { + bounds: axisY.bounds, + chartRect: chartRect, + axisX: axisX, + axisY: axisY, + svg: this.svg, + options: options + }); + } + }]); + + return LineChart; +}(BaseChart); + +/** + * Default options in bar charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Bar + */ +var defaultOptions$2 = { + // Options for X-Axis + axisX: { + // The offset of the chart drawing area to the border of the container + offset: 30, + // 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. + position: 'end', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // This value specifies the minimum width in pixel of the scale steps + scaleMinSpace: 30, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false + }, + // Options for Y-Axis + axisY: { + // The offset of the chart drawing area to the border of the container + offset: 40, + // 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. + position: 'start', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false + }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + high: undefined, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + low: undefined, + // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale. + referenceValue: 0, + // 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} + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, + // Specify the distance in pixel of bars in a group + seriesBarDistance: 15, + // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options. + stackBars: false, + // If set to 'overlap' this property will force the stacked bars to draw from the zero line. + // 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. + stackMode: 'accumulate', + // 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. + horizontalBars: false, + // 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. + distributeSeries: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // If the bar chart should add a background fill to the .ct-grids group. + showGridBackground: false, + // Override the class names that get used to generate the SVG structure of the chart + 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' + } +}; + +var BarChart = function (_BaseChart) { + _inherits(BarChart, _BaseChart); + + /** + * This method creates a new bar chart and returns API object that you can use for later changes. + * + * @memberof Chartist.Bar + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // Create a simple bar chart + * var data = { + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // 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. + * new Chartist.Bar('.ct-chart', data); + * + * @example + * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 + * new Chartist.Bar('.ct-chart', { + * labels: [1, 2, 3, 4, 5, 6, 7], + * series: [ + * [1, 3, 2, -5, -3, 1, -6], + * [-5, -2, -4, -1, 2, -3, 1] + * ] + * }, { + * seriesBarDistance: 12, + * low: -10, + * high: 10 + * }); + * + */ + function BarChart(query, data, options, responsiveOptions) { + _classCallCheck(this, BarChart); + + return _possibleConstructorReturn(this, (BarChart.__proto__ || Object.getPrototypeOf(BarChart)).call(this, query, data, defaultOptions$2, extend({}, defaultOptions$2, options), responsiveOptions)); + } + + /** + * Creates a new chart + * + */ + + + _createClass(BarChart, [{ + key: 'createChart', + value: function createChart(options) { + var data; + var highLow; + + if (options.distributeSeries) { + data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + data.normalized.series = data.normalized.series.map(function (value) { + return [value]; + }); + } else { + data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + } + + // Create new svg element + this.svg = createSvg(this.container, options.width, options.height, options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '')); + + // Drawing groups in correct order + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + + if (options.stackBars && data.normalized.series.length !== 0) { + + // If stacked bars we need to calculate the high low from stacked values from each series + var serialSums = serialMap(data.normalized.series, function serialSums() { + return Array.prototype.slice.call(arguments).map(function (value) { + return value; + }).reduce(function (prev, curr) { + return { + x: prev.x + (curr && curr.x) || 0, + y: prev.y + (curr && curr.y) || 0 + }; + }, { x: 0, y: 0 }); + }); + + highLow = getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y'); + } else { + + highLow = getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y'); + } + + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); + + var chartRect = createChartRect(this.svg, options, defaultOptions$2.padding); + + var valueAxis, labelAxisTicks, labelAxis, axisX, axisY; + + // We need to set step count based on some options combinations + if (options.distributeSeries && options.stackBars) { + // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should + // use only the first label for the step axis + labelAxisTicks = data.normalized.labels.slice(0, 1); + } else { + // If distributed series are enabled but stacked bars aren't, we should use the series labels + // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array + // as the bars are normalized + labelAxisTicks = data.normalized.labels; + } + + // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. + if (options.horizontalBars) { + if (options.axisX.type === undefined) { + valueAxis = axisX = new AutoScaleAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } + + if (options.axisY.type === undefined) { + labelAxis = axisY = new StepAxis(axisUnits.y, data.normalized.series, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, options.axisY); + } + } else { + if (options.axisX.type === undefined) { + labelAxis = axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX); + } + + if (options.axisY.type === undefined) { + valueAxis = axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisY = new options.axisY.type(axisUnits.units.y, data.normalized.series, chartRect, extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } + } + + // Projected 0 point + var zeroPoint = options.horizontalBars ? chartRect.x1 + valueAxis.projectValue(0) : chartRect.y1 - valueAxis.projectValue(0); + // Used to track the screen coordinates of stacked bars + var stackedBarValues = []; + + labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + + if (options.showGridBackground) { + createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + + // Draw the series + data.raw.series.forEach(function (series, seriesIndex) { + // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. + var biPol = seriesIndex - (data.raw.series.length - 1) / 2; + // Half of the period width between vertical grid lines used to position bars + var periodHalfLength; + // Current series SVG element + var seriesElement; + + // We need to set periodHalfLength based on some options combinations + if (options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array + // which is the series count and divide by 2 + periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2; + } else if (options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis + // length by 2 + periodHalfLength = labelAxis.axisLength / 2; + } else { + // On regular bar charts we should just use the series length + periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2; + } + + // Adding the series group to the series element + seriesElement = seriesGroup.elem('g'); + + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesElement.attr({ + 'ct:series-name': series.name, + 'ct:meta': serialize(series.meta) + }); + + // Use series class from series data or if not set generate one + seriesElement.addClass([options.classNames.series, series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)].join(' ')); + + data.normalized.series[seriesIndex].forEach(function (value, valueIndex) { + var projected, bar, previousStack, labelAxisValueIndex; + + // We need to set labelAxisValueIndex based on some options combinations + if (options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection + // on the step axis for label positioning + labelAxisValueIndex = seriesIndex; + } else if (options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use + // 0 for projection on the label step axis + labelAxisValueIndex = 0; + } else { + // On regular bar charts we just use the value index to project on the label step axis + labelAxisValueIndex = valueIndex; + } + + // We need to transform coordinates differently based on the chart layout + if (options.horizontalBars) { + projected = { + x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]) + }; + } else { + projected = { + x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex]) + }; + } + + // If the label axis is a step based axis we will offset the bar into the middle of between two steps using + // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using + // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not + // add any automated positioning. + if (labelAxis instanceof StepAxis) { + // Offset to center bar between grid lines, but only if the step axis is not stretched + if (!labelAxis.options.stretch) { + projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); + } + // Using bi-polar offset for multiple series if no stacked bars or series distribution is used + projected[labelAxis.units.pos] += options.stackBars || options.distributeSeries ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + } + + // Enter value in stacked bar values used to remember previous screen value for stacking up bars + previousStack = stackedBarValues[valueIndex] || zeroPoint; + stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); + + // Skip if value is undefined + if (value === undefined) { + return; + } + + var positions = {}; + positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; + positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; + + if (options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) { + // Stack mode: accumulate (default) + // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line + // We want backwards compatibility, so the expected fallback without the 'stackMode' option + // to be the original behaviour (accumulate) + positions[labelAxis.counterUnits.pos + '1'] = previousStack; + positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; + } else { + // Draw from the zero line normally + // This is also the same code for Stack mode: overlap + positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; + } + + // Limit x and y so that they are within the chart rect + positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); + positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2); + positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); + positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); + + var metaData = getMetaData(series, valueIndex); + + // Create bar element + bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ + 'ct:value': [value.x, value.y].filter(isNumeric).join(','), + 'ct:meta': serialize(metaData) + }); + + this.eventEmitter.emit('draw', extend({ + type: 'bar', + value: value, + index: valueIndex, + meta: metaData, + series: series, + seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, + chartRect: chartRect, + group: seriesElement, + element: bar + }, positions)); + }.bind(this)); + }.bind(this)); + + this.eventEmitter.emit('created', { + bounds: valueAxis.bounds, + chartRect: chartRect, + axisX: axisX, + axisY: axisY, + svg: this.svg, + options: options + }); + } + }]); + + return BarChart; +}(BaseChart); + +/** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Pie + */ +var defaultOptions$3 = { + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // 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} + chartPadding: 5, + // Override the class names that are used to generate the SVG structure of the chart + classNames: { + chartPie: 'ct-chart-pie', + chartDonut: 'ct-chart-donut', + series: 'ct-series', + slicePie: 'ct-slice-pie', + sliceDonut: 'ct-slice-donut', + label: 'ct-label' + }, + // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. + startAngle: 0, + // 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. + total: undefined, + // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. + donut: 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, + // If a label should be shown or not + showLabel: true, + // 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. + labelOffset: 0, + // 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. + labelPosition: 'inside', + // An interpolation function for the label value + labelInterpolationFnc: noop, + // 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. + labelDirection: 'neutral', + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // If true empty values will be ignored to avoid drawing unncessary slices and labels + ignoreEmptyValues: false +}; + +/** + * Determines SVG anchor position based on direction and center parameter + * + * @param center + * @param label + * @param direction + * @return {string} + */ +function determineAnchorPosition(center, label, direction) { + var toTheRight = label.x > center.x; + + if (toTheRight && direction === 'explode' || !toTheRight && direction === 'implode') { + return 'start'; + } else if (toTheRight && direction === 'implode' || !toTheRight && direction === 'explode') { + return 'end'; + } else { + return 'middle'; + } +} + +var PieChart = function (_BaseChart) { + _inherits(PieChart, _BaseChart); + + /** + * This method creates a new pie chart and returns an object that can be used to redraw the chart. + * + * @memberof Chartist.Pie + * @param {String|Node} query A selector query string or directly a DOM element + * @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. + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object with a version and an update method to manually redraw the chart + * + * @example + * // Simple pie chart example with four series + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }); + * + * @example + * // Drawing a donut chart + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }, { + * donut: true + * }); + * + * @example + * // Using donut, startAngle and total to draw a gauge chart + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * donut: true, + * donutWidth: 20, + * startAngle: 270, + * total: 200 + * }); + * + * @example + * // Drawing a pie chart with padding and labels that are outside the pie + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * chartPadding: 30, + * labelOffset: 50, + * labelDirection: 'explode' + * }); + * + * @example + * // Overriding the class names for individual series as well as a name and meta data. + * // The name will be written as ct:series-name attribute and the meta data will be serialized and written + * // to a ct:meta attribute. + * new Chartist.Pie('.ct-chart', { + * series: [{ + * value: 20, + * name: 'Series 1', + * className: 'my-custom-class-one', + * meta: 'Meta One' + * }, { + * value: 10, + * name: 'Series 2', + * className: 'my-custom-class-two', + * meta: 'Meta Two' + * }, { + * value: 70, + * name: 'Series 3', + * className: 'my-custom-class-three', + * meta: 'Meta Three' + * }] + * }); + */ + function PieChart(query, data, options, responsiveOptions) { + _classCallCheck(this, PieChart); + + return _possibleConstructorReturn(this, (PieChart.__proto__ || Object.getPrototypeOf(PieChart)).call(this, query, data, defaultOptions$3, extend({}, defaultOptions$3, options), responsiveOptions)); + } + + /** + * Creates the pie chart + * + * @param options + */ + + + _createClass(PieChart, [{ + key: 'createChart', + value: function createChart(options) { + var data = normalizeData(this.data); + var seriesGroups = [], + labelsGroup, + chartRect, + radius, + labelRadius, + totalDataSum, + startAngle = options.startAngle; + + // Create SVG.js draw + this.svg = createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie); + // Calculate charting rect + chartRect = createChartRect(this.svg, options, defaultOptions$3.padding); + // Get biggest circle radius possible within chartRect + radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + // Calculate total of all series to get reference value or use total reference from optional options + totalDataSum = options.total || data.normalized.series.reduce(function (previousValue, currentValue) { + return previousValue + currentValue; + }, 0); + + var donutWidth = quantity(options.donutWidth); + if (donutWidth.unit === '%') { + donutWidth.value *= radius / 100; + } + + // 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; + + // 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) { + 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 { + // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie + // slice + labelRadius = radius / 2; + } + // Add the offset to the labelRadius where a negative offset means closed to the center of the chart + labelRadius += options.labelOffset; + + // Calculate end angle based on total sum and current data value and offset with padding + var center = { + x: chartRect.x1 + chartRect.width() / 2, + y: chartRect.y2 + chartRect.height() / 2 + }; + + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = data.raw.series.filter(function (val) { + return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; + }).length === 1; + + // Creating the series groups + data.raw.series.forEach(function (series, index) { + seriesGroups[index] = this.svg.elem('g', null, null); + }.bind(this)); + //if we need to show labels we create the label group now + if (options.showLabel) { + labelsGroup = this.svg.elem('g', null, null); + } + + // Draw the series + // initialize series groups + data.raw.series.forEach(function (series, index) { + // If current value is zero and we are ignoring empty values then skip to next value + if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; + + // If the series is an object and contains a name or meta data we add a custom attribute + seriesGroups[index].attr({ + 'ct:series-name': series.name + }); + + // Use series class from series data or if not set generate one + seriesGroups[index].addClass([options.classNames.series, series.className || options.classNames.series + '-' + alphaNumerate(index)].join(' ')); + + // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. + var endAngle = totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0; + + // Use slight offset so there are no transparent hairline issues + var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); + + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle + // with Z and use 359.99 degrees + if (endAngle - overlappigStartAngle >= 359.99) { + endAngle = overlappigStartAngle + 359.99; + } + + var start = polarToCartesian(center.x, center.y, radius, overlappigStartAngle), + end = polarToCartesian(center.x, center.y, radius, endAngle); + + // 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 SvgPath(!options.donut).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); + } + + // Create the SVG path + // If this is a donut chart we add the donut class, otherwise just a regular slice + var pathElement = seriesGroups[index].elem('path', { + d: path.stringify() + }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie); + + // Adding the pie series value to the path + pathElement.attr({ + 'ct:value': data.normalized.series[index], + 'ct:meta': serialize(series.meta) + }); + + // If this is a donut, we add the stroke-width as style attribute + if (options.donut) { + pathElement.attr({ + 'style': 'stroke-width: ' + donutWidth.value + 'px' + }); + } + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'slice', + value: data.normalized.series[index], + totalDataSum: totalDataSum, + index: index, + meta: series.meta, + series: series, + group: seriesGroups[index], + element: pathElement, + path: path.clone(), + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + + // If we need to show labels we need to add the label for this slice now + if (options.showLabel) { + var labelPosition; + if (data.raw.series.length === 1) { + // If we have only 1 series, we can position the label in the center of the pie + labelPosition = { + x: center.x, + y: center.y + }; + } else { + // Position at the labelRadius distance from center and between start and end angle + labelPosition = polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2); + } + + var rawValue; + if (data.normalized.labels && !isFalseyButZero(data.normalized.labels[index])) { + rawValue = data.normalized.labels[index]; + } else { + rawValue = data.normalized.series[index]; + } + + var interpolatedValue = options.labelInterpolationFnc(rawValue, index); + + if (interpolatedValue || interpolatedValue === 0) { + var labelElement = labelsGroup.elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: index, + group: labelsGroup, + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } + } + + // Set next startAngle to current endAngle. + // (except for last slice) + startAngle = endAngle; + }.bind(this)); + + this.eventEmitter.emit('created', { + chartRect: chartRect, + svg: this.svg, + options: options + }); + } + }]); + + return PieChart; +}(BaseChart); + +export { interpolation as Interpolation, EventEmitter, extend, optionsProvider, namespaces, precision, escapingMap, version, replaceAll, querySelector$1 as querySelector, safeHasProperty, isNumeric, isFalseyButZero, getNumberOrUndefined, ensureUnit, quantity, alphaNumerate, noop, times, sum, mapMultiply, mapAdd, serialMap, orderOfMagnitude, projectLength, roundWithPrecision, rho, polarToCartesian, serialize, deserialize, normalizeData, getMetaData, isDataHoleValue, reverseData, getDataArray, isMultiValue, getMultiValue, getSeriesOption, splitIntoSegments, getHighLow, getBounds, createSvg, normalizePadding, createChartRect, createGrid, createGridBackground, createLabel, BaseChart, LineChart, BarChart, PieChart, Axis, axisUnits, AutoScaleAxis, FixedScaleAxis, StepAxis, Svg, isSupported, easings, SvgList, SvgPath }; + +//# sourceMappingURL=chartist.esm.js.map \ No newline at end of file diff --git a/dist/chartist.esm.js.map b/dist/chartist.esm.js.map new file mode 100644 index 00000000..b231d866 --- /dev/null +++ b/dist/chartist.esm.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../package.json!file:/home/gion/Code/chartist/tooling/system-loaders/package.json","../src/core/globals.js","../src/core/lang.js","../src/core/functional.js","../src/core/math.js","../src/core/extend.js","../src/core/data.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/classCallCheck.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/createClass.js","../src/svg/svg-list.js","../src/svg/svg.js","../src/core/creation.js","../src/core/options-provider.js","../src/event/event-emitter.js","../src/charts/base.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/possibleConstructorReturn.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/inherits.js","../src/axes/axis.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/get.js","../src/axes/auto-scale-axis.js","../src/axes/fixed-scale-axis.js","../src/axes/step-axis.js","../src/svg/svg-path.js","../src/interpolation/none.js","../src/interpolation/simple.js","../src/interpolation/step.js","../src/interpolation/cardinal.js","../src/interpolation/monotone-cubic.js","../src/charts/line.js","../src/charts/bar.js","../src/charts/pie.js"],"names":["version","namespaces","precision","escapingMap","replaceAll","str","subStr","newSubStr","replace","RegExp","querySelector","query","Node","document","safeHasProperty","object","property","hasOwnProperty","isNumeric","value","isFinite","isFalseyButZero","getNumberOrUndefined","undefined","ensureUnit","unit","quantity","input","match","exec","alphaNumerate","n","String","fromCharCode","noop","times","length","Array","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","forEach","index","args","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","roundWithPrecision","digits","pow","round","rho","gcd","p","q","f","x","x1","x2","divisor","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","extend","target","i","source","sourceProp","arguments","prop","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","normalizeData","reverse","multi","labelCount","output","normalized","series","getDataArray","every","labels","slice","prototype","push","getMetaData","meta","isDataHoleValue","isNaN","reverseData","recursiveConvert","multiValue","y","isMultiValue","getMultiValue","dimension","getSeriesOption","options","name","seriesOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","segments","hole","fillHoles","increasingX","getHighLow","toUpperCase","highLow","high","Number","MAX_VALUE","low","findHigh","findLow","recursiveHighLow","referenceValue","min","getBounds","scaleMinSpace","onlyInteger","optimizationCounter","newMin","newMax","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","EPSILON","safeIncrement","increment","values","instance","Constructor","TypeError","defineProperties","props","descriptor","enumerable","configurable","writable","defineProperty","protoProps","staticProps","SvgList","nodeList","list","svgElements","Svg","filter","prototypeProperty","indexOf","call","element","attributes","className","parent","insertFirst","Element","_node","createElementNS","svg","attr","ct","addClass","firstChild","insertBefore","appendChild","ns","getAttributeNS","getAttribute","namespacedAttribute","split","setAttributeNS","setAttribute","bind","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","querySelectorAll","content","container","createElement","innerHTML","xmlns","fnObj","elem","t","createTextNode","removeChild","newElement","replaceChild","trim","names","classes","concat","pos","self","join","removedClasses","getBoundingClientRect","height","width","animations","guided","eventEmitter","createAnimateForAttributes","attribute","createAnimate","animationDefinition","attributeProperties","animate","timeout","animationEasing","easing","easings","begin","dur","calcMode","keySplines","keyTimes","fill","from","beginElement","err","to","remove","addEventListener","handleBeginEvent","emit","handleEndEvent","isSupported","feature","implementation","hasFeature","createSvg","filterChartistSvgObjects","removePreviousElement","normalizePadding","padding","fallback","top","right","bottom","left","createChartRect","fallbackPadding","hasAxis","axisX","axisY","yAxisOffset","offset","xAxisOffset","normalizedPadding","chartPadding","chartRect","y1","y2","position","createGrid","axis","group","positionalData","units","counterUnits","gridElement","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","foreignObject","text","optionsProvider","responsiveOptions","baseOptions","currentOptions","mediaQueryListeners","updateCurrentOptions","mediaEvent","previousOptions","mql","window","matchMedia","matches","removeMediaQueryListeners","removeListener","addListener","getCurrentOptions","EventEmitter","handlers","event","handler","splice","starHandler","BaseChart","supportsForeignObject","supportsAnimations","resizeListener","update","__chartist__","detach","initializeTimeoutId","setTimeout","initialize","override","createChart","removeEventListener","clearTimeout","addEventHandler","removeEventHandler","plugins","plugin","ReferenceError","subClass","superClass","create","setPrototypeOf","__proto__","axisUnits","Axis","ticks","rectEnd","rectStart","gridOffset","rectOffset","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","get","receiver","Function","desc","getOwnPropertyDescriptor","getPrototypeOf","getter","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","a","b","stepLength","StepAxis","calc","stretch","elementDescriptions","command","params","pathElements","relative","pathElement","toLowerCase","forEachParam","pathElementIndex","paramName","paramIndex","SvgPath","paths","close","joinedPath","path","j","count","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","transformFnc","transformed","c","cloneElements","none","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","postpone","cardinal","tension","segment","z","iLen","monotoneCubic","xs","ys","ms","ds","dys","dxs","LineChart","chart","seriesGroup","type","fullWidth","createGridAndLabels","showGridBackground","raw","seriesIndex","seriesElement","pathData","valueIndex","smoothing","lineSmooth","showPoint","point","showLine","clone","showArea","areaBase","areaBaseProjected","splitByCommand","onlySolidSegments","pathSegment","convertToArea","solidPathSegments","firstElement","lastElement","createArea","areaPath","area","BarChart","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","biPol","periodHalfLength","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","stackMode","metaData","determineAnchorPosition","center","direction","toTheRight","PieChart","seriesGroups","labelsGroup","labelRadius","totalDataSum","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","start","end","arc","sliceDonut","slicePie","rawValue","interpolatedValue","labelDirection"],"mappings":"AAAO,IAAMA,UAAU,OAAhB;;ACEP;;;;;AAKA,AAAO,IAAIC,aAAa;OACjB,4BADiB;SAEf,+BAFe;SAGf,8BAHe;SAIf,8BAJe;MAKlB;CALC;;;;;;;AAaP,AAAO,IAAIC,YAAY,CAAhB;;;;;;;AAOP,AAAO,IAAIC,cAAc;OAClB,OADkB;OAElB,MAFkB;OAGlB,MAHkB;OAIlB,QAJkB;QAKjB;CALD;;AC3BP;;;;;;;;AAQA,AAAO,SAASC,UAAT,CAAoBC,GAApB,EAAyBC,MAAzB,EAAiCC,SAAjC,EAA4C;SAC1CF,IAAIG,OAAJ,CAAY,IAAIC,MAAJ,CAAWH,MAAX,EAAmB,GAAnB,CAAZ,EAAqCC,SAArC,CAAP;;;;;;;;;;AAUF,AAAO,SAASG,eAAT,CAAuBC,KAAvB,EAA8B;SAC5BA,iBAAiBC,IAAjB,GAAwBD,KAAxB,GAAgCE,SAASH,aAAT,CAAuBC,KAAvB,CAAvC;;;;;;;;;;AAUF,AAAO,SAASG,eAAT,CAAyBC,MAAzB,EAAiCC,QAAjC,EAA2C;SACzCD,WAAW,IAAX,IACL,OAAOA,MAAP,KAAkB,QADb,IAELA,OAAOE,cAAP,CAAsBD,QAAtB,CAFF;;;;;;;;;;AAYF,AAAO,SAASE,SAAT,CAAmBC,KAAnB,EAA0B;SACxBA,UAAU,IAAV,GAAiB,KAAjB,GAAyBC,SAASD,KAAT,CAAhC;;;;;;;;;;AAUF,AAAO,SAASE,eAAT,CAAyBF,KAAzB,EAAgC;SAC9B,CAACA,KAAD,IAAUA,UAAU,CAA3B;;;;;;;;;;AAUF,AAAO,SAASG,oBAAT,CAA8BH,KAA9B,EAAqC;SACnCD,UAAUC,KAAV,IAAmB,CAACA,KAApB,GAA4BI,SAAnC;;;;;;;;;;;AAWF,AAAO,SAASC,UAAT,CAAoBL,KAApB,EAA2BM,IAA3B,EAAiC;MACnC,OAAON,KAAP,KAAiB,QAApB,EAA8B;YACpBA,QAAQM,IAAhB;;;SAGKN,KAAP;;;;;;;;;;AAUF,AAAO,SAASO,QAAT,CAAkBC,KAAlB,EAAyB;MAC1B,OAAOA,KAAP,KAAiB,QAArB,EAA+B;QACzBC,QAAS,iBAAD,CAAoBC,IAApB,CAAyBF,KAAzB,CAAZ;WACO;aACG,CAACC,MAAM,CAAN,CADJ;YAECA,MAAM,CAAN,KAAYL;KAFpB;;SAKK,EAAEJ,OAAOQ,KAAT,EAAP;;;;;;;;;;AAUF,AAAO,SAASG,aAAT,CAAuBC,CAAvB,EAA0B;;SAExBC,OAAOC,YAAP,CAAoB,KAAKF,IAAI,EAA7B,CAAP;;;AChHF;;;;;;;AAOA,AAAO,SAASG,IAAT,CAAcH,CAAd,EAAiB;SACfA,CAAP;;;;;;;;;;AAUF,AAAO,SAASI,KAAT,CAAeC,MAAf,EAAuB;SACrBC,MAAMC,KAAN,CAAY,IAAZ,EAAkB,IAAID,KAAJ,CAAUD,MAAV,CAAlB,CAAP;;;;;;;;;;;AAWF,AAAO,SAASG,GAAT,CAAaC,QAAb,EAAuBC,OAAvB,EAAgC;SAC9BD,YAAYC,UAAUA,OAAV,GAAoB,CAAhC,CAAP;;;;;;;;;;AAUF,AAAO,SAASC,WAAT,CAAqBC,MAArB,EAA6B;SAC3B,UAASC,GAAT,EAAc;WACZA,MAAMD,MAAb;GADF;;;;;;;;;;AAYF,AAAO,SAASE,MAAT,CAAgBC,MAAhB,EAAwB;SACtB,UAASF,GAAT,EAAc;WACZA,MAAME,MAAb;GADF;;;;;;;;;;;AAaF,AAAO,SAASC,SAAT,CAAmBC,GAAnB,EAAwBC,EAAxB,EAA4B;MAC7BC,SAAS,EAAb;MACEd,SAASe,KAAKC,GAAL,CAASd,KAAT,CAAe,IAAf,EAAqBU,IAAIK,GAAJ,CAAQ,UAASC,CAAT,EAAY;WACzCA,EAAElB,MAAT;GAD4B,CAArB,CADX;;QAKMA,MAAN,EAAcmB,OAAd,CAAsB,UAASD,CAAT,EAAYE,KAAZ,EAAmB;QACnCC,OAAOT,IAAIK,GAAJ,CAAQ,UAASC,CAAT,EAAY;aACtBA,EAAEE,KAAF,CAAP;KADS,CAAX;;WAIOA,KAAP,IAAgBP,GAAGX,KAAH,CAAS,IAAT,EAAemB,IAAf,CAAhB;GALF;;SAQOP,MAAP;;;AChFF;;;;;;;AAOA,AAAO,SAASQ,gBAAT,CAA0BvC,KAA1B,EAAiC;SAC/BgC,KAAKQ,KAAL,CAAWR,KAAKS,GAAL,CAAST,KAAKU,GAAL,CAAS1C,KAAT,CAAT,IAA4BgC,KAAKW,IAA5C,CAAP;;;;;;;;;;;;AAYF,AAAO,SAASC,aAAT,CAAuBC,UAAvB,EAAmC5B,MAAnC,EAA2C6B,MAA3C,EAAmD;SACjD7B,SAAS6B,OAAOC,KAAhB,GAAwBF,UAA/B;;;;;;;;;;;AAWF,AAAO,SAASG,kBAAT,CAA4BhD,KAA5B,EAAmCiD,MAAnC,EAA2C;MAC5ClE,eAAYiD,KAAKkB,GAAL,CAAS,EAAT,EAAaD,UAAUlE,YAAvB,CAAhB;SACOiD,KAAKmB,KAAL,CAAWnD,QAAQjB,YAAnB,IAAgCA,YAAvC;;;;;;;;;;AAUF,AAAO,SAASqE,GAAT,CAAa3B,GAAb,EAAkB;MACpBA,QAAQ,CAAX,EAAc;WACLA,GAAP;;;WAGO4B,GAAT,CAAaC,CAAb,EAAgBC,CAAhB,EAAmB;QACbD,IAAIC,CAAJ,KAAU,CAAd,EAAiB;aACRA,CAAP;KADF,MAEO;aACEF,IAAIE,CAAJ,EAAOD,IAAIC,CAAX,CAAP;;;;WAIKC,CAAT,CAAWC,CAAX,EAAc;WACLA,IAAIA,CAAJ,GAAQ,CAAf;;;MAGEC,KAAK,CAAT;MAAYC,KAAK,CAAjB;MAAoBC,OAApB;MACInC,MAAM,CAAN,KAAY,CAAhB,EAAmB;WACV,CAAP;;;KAGC;SACI+B,EAAEE,EAAF,IAAQjC,GAAb;SACK+B,EAAEA,EAAEG,EAAF,CAAF,IAAWlC,GAAhB;cACU4B,IAAIrB,KAAKU,GAAL,CAASgB,KAAKC,EAAd,CAAJ,EAAuBlC,GAAvB,CAAV;GAHF,QAISmC,YAAY,CAJrB;;SAMOA,OAAP;;;;;;;;;;;;;AAaF,AAAO,SAASC,gBAAT,CAA0BC,OAA1B,EAAmCC,OAAnC,EAA4CC,MAA5C,EAAoDC,cAApD,EAAoE;MACrEC,iBAAiB,CAACD,iBAAiB,EAAlB,IAAwBjC,KAAKmC,EAA7B,GAAkC,KAAvD;;SAEO;OACFL,UAAWE,SAAShC,KAAKoC,GAAL,CAASF,cAAT,CADlB;OAEFH,UAAWC,SAAShC,KAAKqC,GAAL,CAASH,cAAT;GAFzB;;;AC1FF;;;;;;;;AAQA,AAAO,SAASI,MAAT,CAAgBC,MAAhB,EAAwB;MACzBC,CAAJ,EAAOC,MAAP,EAAeC,UAAf;WACSH,UAAU,EAAnB;;OAEKC,IAAI,CAAT,EAAYA,IAAIG,UAAU1D,MAA1B,EAAkCuD,GAAlC,EAAuC;aAC5BG,UAAUH,CAAV,CAAT;SACK,IAAII,IAAT,IAAiBH,MAAjB,EAAyB;mBACVA,OAAOG,IAAP,CAAb;UACI,OAAOF,UAAP,KAAsB,QAAtB,IAAkCA,eAAe,IAAjD,IAAyD,EAAEA,sBAAsBxD,KAAxB,CAA7D,EAA6F;eACpF0D,IAAP,IAAeN,OAAOC,OAAOK,IAAP,CAAP,EAAqBF,UAArB,CAAf;OADF,MAEO;eACEE,IAAP,IAAeF,UAAf;;;;;SAKCH,MAAP;;;AClBF;;;;;;;;AAQA,AAAO,SAASM,SAAT,CAAmBC,IAAnB,EAAyB;MAC3BA,SAAS,IAAT,IAAiBA,SAAS1E,SAA7B,EAAwC;WAC/B0E,IAAP;GADF,MAEO,IAAG,OAAOA,IAAP,KAAgB,QAAnB,EAA6B;WAC3B,KAAGA,IAAV;GADK,MAEA,IAAG,OAAOA,IAAP,KAAgB,QAAnB,EAA6B;WAC3BC,KAAKC,SAAL,CAAe,EAACF,MAAMA,IAAP,EAAf,CAAP;;;SAGKG,OAAOC,IAAP,CAAYlG,WAAZ,EAAyBmG,MAAzB,CAAgC,UAASpD,MAAT,EAAiBqD,GAAjB,EAAsB;WACpDnG,WAAW8C,MAAX,EAAmBqD,GAAnB,EAAwBpG,YAAYoG,GAAZ,CAAxB,CAAP;GADK,EAEJN,IAFI,CAAP;;;;;;;;;;AAYF,AAAO,SAASO,WAAT,CAAqBP,IAArB,EAA2B;MAC7B,OAAOA,IAAP,KAAgB,QAAnB,EAA6B;WACpBA,IAAP;;;SAGKG,OAAOC,IAAP,CAAYlG,WAAZ,EAAyBmG,MAAzB,CAAgC,UAASpD,MAAT,EAAiBqD,GAAjB,EAAsB;WACpDnG,WAAW8C,MAAX,EAAmB/C,YAAYoG,GAAZ,CAAnB,EAAqCA,GAArC,CAAP;GADK,EAEJN,IAFI,CAAP;;MAII;WACKC,KAAKO,KAAL,CAAWR,IAAX,CAAP;WACOA,KAAKA,IAAL,KAAc1E,SAAd,GAA0B0E,KAAKA,IAA/B,GAAsCA,IAA7C;GAFF,CAGE,OAAM3C,CAAN,EAAS;;SAEJ2C,IAAP;;;;;;;;;AASF,AAAO,SAASS,aAAT,CAAuBT,IAAvB,EAA6BU,OAA7B,EAAsCC,KAAtC,EAA6C;MAC9CC,UAAJ;MACIC,SAAS;SACNb,IADM;gBAEC;GAFd;;;SAMOc,UAAP,CAAkBC,MAAlB,GAA2BC,aAAa;YAC9BhB,KAAKe,MAAL,IAAe;GADE,EAExBL,OAFwB,EAEfC,KAFe,CAA3B;;;;MAMIE,OAAOC,UAAP,CAAkBC,MAAlB,CAAyBE,KAAzB,CAA+B,UAAS/F,KAAT,EAAgB;WACxCA,iBAAiBkB,KAAxB;GADA,CAAJ,EAEM;;iBAESc,KAAKC,GAAL,CAASd,KAAT,CAAe,IAAf,EAAqBwE,OAAOC,UAAP,CAAkBC,MAAlB,CAAyB3D,GAAzB,CAA6B,UAAS2D,MAAT,EAAiB;aACvEA,OAAO5E,MAAd;KADgC,CAArB,CAAb;GAJF,MAOO;;iBAEQ0E,OAAOC,UAAP,CAAkBC,MAAlB,CAAyB5E,MAAtC;;;SAGK2E,UAAP,CAAkBI,MAAlB,GAA2B,CAAClB,KAAKkB,MAAL,IAAe,EAAhB,EAAoBC,KAApB,EAA3B;;QAEMC,SAAN,CAAgBC,IAAhB,CAAqBhF,KAArB,CACEwE,OAAOC,UAAP,CAAkBI,MADpB,EAEEhF,MAAMgB,KAAKC,GAAL,CAAS,CAAT,EAAYyD,aAAaC,OAAOC,UAAP,CAAkBI,MAAlB,CAAyB/E,MAAlD,CAAN,EAAiEiB,GAAjE,CAAqE,YAAW;WACvE,EAAP;GADF,CAFF;;MAOGsD,OAAH,EAAY;gBACEG,OAAOC,UAAnB;;;SAGKD,MAAP;;;;;;;;;;AAUF,AAAO,SAASS,WAAT,CAAqBP,MAArB,EAA6BxD,KAA7B,EAAoC;MACrCrC,QAAQ6F,OAAOf,IAAP,GAAce,OAAOf,IAAP,CAAYzC,KAAZ,CAAd,GAAmCwD,OAAOxD,KAAP,CAA/C;SACOrC,QAAQA,MAAMqG,IAAd,GAAqBjG,SAA5B;;;;;;;;;AASF,AAAO,SAASkG,eAAT,CAAyBtG,KAAzB,EAAgC;SAC9BA,UAAU,IAAV,IACLA,UAAUI,SADL,IAEJ,OAAOJ,KAAP,KAAiB,QAAjB,IAA6BuG,MAAMvG,KAAN,CAFhC;;;;;;;;;AAWF,AAAO,SAASwG,WAAT,CAAqB1B,IAArB,EAA2B;OAC3BkB,MAAL,CAAYR,OAAZ;OACKK,MAAL,CAAYL,OAAZ;OACK,IAAIhB,IAAI,CAAb,EAAgBA,IAAIM,KAAKe,MAAL,CAAY5E,MAAhC,EAAwCuD,GAAxC,EAA6C;QACxC,OAAOM,KAAKe,MAAL,CAAYrB,CAAZ,CAAP,KAA2B,QAA3B,IAAuCM,KAAKe,MAAL,CAAYrB,CAAZ,EAAeM,IAAf,KAAwB1E,SAAlE,EAA6E;WACtEyF,MAAL,CAAYrB,CAAZ,EAAeM,IAAf,CAAoBU,OAApB;KADF,MAEO,IAAGV,KAAKe,MAAL,CAAYrB,CAAZ,aAA0BtD,KAA7B,EAAoC;WACpC2E,MAAL,CAAYrB,CAAZ,EAAegB,OAAf;;;;;;;;;;;;;;AAcN,AAAO,SAASM,YAAT,CAAsBhB,IAAtB,EAA4BU,OAA5B,EAAqCC,KAArC,EAA4C;;;WAGxCgB,gBAAT,CAA0BzG,KAA1B,EAAiC;QAC5BL,gBAAgBK,KAAhB,EAAuB,OAAvB,CAAH,EAAoC;;aAE3ByG,iBAAiBzG,MAAMA,KAAvB,CAAP;KAFF,MAGO,IAAGL,gBAAgBK,KAAhB,EAAuB,MAAvB,CAAH,EAAmC;;aAEjCyG,iBAAiBzG,MAAM8E,IAAvB,CAAP;KAFK,MAGA,IAAG9E,iBAAiBkB,KAApB,EAA2B;;aAEzBlB,MAAMkC,GAAN,CAAUuE,gBAAV,CAAP;KAFK,MAGA,IAAGH,gBAAgBtG,KAAhB,CAAH,EAA2B;;;aAGzBI,SAAP;KAHK,MAIA;;UAEFqF,KAAH,EAAU;YACJiB,aAAa,EAAjB;;;;;YAKG,OAAOjB,KAAP,KAAiB,QAApB,EAA8B;qBACjBA,KAAX,IAAoBtF,qBAAqBH,KAArB,CAApB;SADF,MAEO;qBACM2G,CAAX,GAAexG,qBAAqBH,KAArB,CAAf;;;mBAGSyD,CAAX,GAAezD,MAAMF,cAAN,CAAqB,GAArB,IAA4BK,qBAAqBH,MAAMyD,CAA3B,CAA5B,GAA4DiD,WAAWjD,CAAtF;mBACWkD,CAAX,GAAe3G,MAAMF,cAAN,CAAqB,GAArB,IAA4BK,qBAAqBH,MAAM2G,CAA3B,CAA5B,GAA4DD,WAAWC,CAAtF;;eAEOD,UAAP;OAfF,MAiBO;;eAEEvG,qBAAqBH,KAArB,CAAP;;;;;SAKC8E,KAAKe,MAAL,CAAY3D,GAAZ,CAAgBuE,gBAAhB,CAAP;;;;;;;;;AASF,AAAO,SAASG,YAAT,CAAsB5G,KAAtB,EAA6B;SAC3B,OAAOA,KAAP,KAAiB,QAAjB,KAA8B,OAAOA,KAAP,IAAgB,OAAOA,KAArD,CAAP;;;;;;;;;;;;AAYF,AAAO,SAAS6G,aAAT,CAAuB7G,KAAvB,EAA8B8G,SAA9B,EAAyC;MAC3CF,aAAa5G,KAAb,CAAH,EAAwB;WACfG,qBAAqBH,MAAM8G,aAAa,GAAnB,CAArB,CAAP;GADF,MAEO;WACE3G,qBAAqBH,KAArB,CAAP;;;;;;;;;;;;;AAaJ,AAAO,SAAS+G,eAAT,CAAyBlB,MAAzB,EAAiCmB,OAAjC,EAA0C5B,GAA1C,EAA+C;MACjDS,OAAOoB,IAAP,IAAeD,QAAQnB,MAAvB,IAAiCmB,QAAQnB,MAAR,CAAeA,OAAOoB,IAAtB,CAApC,EAAiE;QAC3DC,gBAAgBF,QAAQnB,MAAR,CAAeA,OAAOoB,IAAtB,CAApB;WACOC,cAAcpH,cAAd,CAA6BsF,GAA7B,IAAoC8B,cAAc9B,GAAd,CAApC,GAAyD4B,QAAQ5B,GAAR,CAAhE;GAFF,MAGO;WACE4B,QAAQ5B,GAAR,CAAP;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BJ,AAAO,SAAS+B,iBAAT,CAA2BC,eAA3B,EAA4CC,SAA5C,EAAuDL,OAAvD,EAAgE;MACjEM,iBAAiB;iBACN,KADM;eAER;GAFb;;YAKUhD,OAAO,EAAP,EAAWgD,cAAX,EAA2BN,OAA3B,CAAV;;MAEIO,WAAW,EAAf;MACIC,OAAO,IAAX;;OAEI,IAAIhD,IAAI,CAAZ,EAAeA,IAAI4C,gBAAgBnG,MAAnC,EAA2CuD,KAAK,CAAhD,EAAmD;;QAE9CqC,cAAcQ,UAAU7C,IAAI,CAAd,EAAiBxE,KAA/B,MAA0CI,SAA7C,EAAwD;;UAEnD,CAAC4G,QAAQS,SAAZ,EAAuB;eACd,IAAP;;KAHJ,MAKO;UACFT,QAAQU,WAAR,IAAuBlD,KAAK,CAA5B,IAAiC4C,gBAAgB5C,CAAhB,KAAsB4C,gBAAgB5C,IAAE,CAAlB,CAA1D,EAAgF;;eAEvE,IAAP;;;;UAKCgD,IAAH,EAAS;iBACErB,IAAT,CAAc;2BACK,EADL;qBAED;SAFb;;eAKO,KAAP;;;;eAIOoB,SAAStG,MAAT,GAAkB,CAA3B,EAA8BmG,eAA9B,CAA8CjB,IAA9C,CAAmDiB,gBAAgB5C,CAAhB,CAAnD,EAAuE4C,gBAAgB5C,IAAI,CAApB,CAAvE;eACS+C,SAAStG,MAAT,GAAkB,CAA3B,EAA8BoG,SAA9B,CAAwClB,IAAxC,CAA6CkB,UAAU7C,IAAI,CAAd,CAA7C;;;;SAIG+C,QAAP;;;;;;;;;;;;AAYF,AAAO,SAASI,UAAT,CAAoB7C,IAApB,EAA0BkC,OAA1B,EAAmCF,SAAnC,EAA8C;;YAEzCxC,OAAO,EAAP,EAAW0C,OAAX,EAAoBF,YAAYE,QAAQ,SAASF,UAAUc,WAAV,EAAjB,CAAZ,GAAwD,EAA5E,CAAV;;MAEIC,UAAU;UACNb,QAAQc,IAAR,KAAiB1H,SAAjB,GAA6B,CAAC2H,OAAOC,SAArC,GAAiD,CAAChB,QAAQc,IADpD;SAEPd,QAAQiB,GAAR,KAAgB7H,SAAhB,GAA4B2H,OAAOC,SAAnC,GAA+C,CAAChB,QAAQiB;GAF/D;MAIIC,WAAWlB,QAAQc,IAAR,KAAiB1H,SAAhC;MACI+H,UAAUnB,QAAQiB,GAAR,KAAgB7H,SAA9B;;;WAGSgI,gBAAT,CAA0BtD,IAA1B,EAAgC;QAC3BA,SAAS1E,SAAZ,EAAuB;aACdA,SAAP;KADF,MAEO,IAAG0E,gBAAgB5D,KAAnB,EAA0B;WAC1B,IAAIsD,IAAI,CAAb,EAAgBA,IAAIM,KAAK7D,MAAzB,EAAiCuD,GAAjC,EAAsC;yBACnBM,KAAKN,CAAL,CAAjB;;KAFG,MAIA;UACDxE,QAAQ8G,YAAY,CAAChC,KAAKgC,SAAL,CAAb,GAA+B,CAAChC,IAA5C;;UAEIoD,YAAYlI,QAAQ6H,QAAQC,IAAhC,EAAsC;gBAC5BA,IAAR,GAAe9H,KAAf;;;UAGEmI,WAAWnI,QAAQ6H,QAAQI,GAA/B,EAAoC;gBAC1BA,GAAR,GAAcjI,KAAd;;;;;;MAMHkI,YAAYC,OAAf,EAAwB;qBACLrD,IAAjB;;;;;;MAMEkC,QAAQqB,cAAR,IAA0BrB,QAAQqB,cAAR,KAA2B,CAAzD,EAA4D;YAClDP,IAAR,GAAe9F,KAAKC,GAAL,CAAS+E,QAAQqB,cAAjB,EAAiCR,QAAQC,IAAzC,CAAf;YACQG,GAAR,GAAcjG,KAAKsG,GAAL,CAAStB,QAAQqB,cAAjB,EAAiCR,QAAQI,GAAzC,CAAd;;;;;MAKEJ,QAAQC,IAAR,IAAgBD,QAAQI,GAA5B,EAAiC;;QAE3BJ,QAAQI,GAAR,KAAgB,CAApB,EAAuB;cACbH,IAAR,GAAe,CAAf;KADF,MAEO,IAAID,QAAQI,GAAR,GAAc,CAAlB,EAAqB;;cAElBH,IAAR,GAAe,CAAf;KAFK,MAGA,IAAID,QAAQC,IAAR,GAAe,CAAnB,EAAsB;;cAEnBG,GAAR,GAAc,CAAd;KAFK,MAGA;;cAEGH,IAAR,GAAe,CAAf;cACQG,GAAR,GAAc,CAAd;;;;SAIGJ,OAAP;;;;;;;;;;;;;AAaF,AAAO,SAASU,SAAT,CAAmB1F,UAAnB,EAA+BgF,OAA/B,EAAwCW,aAAxC,EAAuDC,WAAvD,EAAoE;MACrEjE,CAAJ;MACEkE,sBAAsB,CADxB;MAEEC,MAFF;MAGEC,MAHF;MAIE9F,SAAS;UACD+E,QAAQC,IADP;SAEFD,QAAQI;GANjB;;SASOY,UAAP,GAAoB/F,OAAOgF,IAAP,GAAchF,OAAOmF,GAAzC;SACOa,GAAP,GAAavG,iBAAiBO,OAAO+F,UAAxB,CAAb;SACOE,IAAP,GAAc/G,KAAKkB,GAAL,CAAS,EAAT,EAAaJ,OAAOgG,GAApB,CAAd;SACOR,GAAP,GAAatG,KAAKQ,KAAL,CAAWM,OAAOmF,GAAP,GAAanF,OAAOiG,IAA/B,IAAuCjG,OAAOiG,IAA3D;SACO9G,GAAP,GAAaD,KAAKgH,IAAL,CAAUlG,OAAOgF,IAAP,GAAchF,OAAOiG,IAA/B,IAAuCjG,OAAOiG,IAA3D;SACOhG,KAAP,GAAeD,OAAOb,GAAP,GAAaa,OAAOwF,GAAnC;SACOW,aAAP,GAAuBjH,KAAKmB,KAAL,CAAWL,OAAOC,KAAP,GAAeD,OAAOiG,IAAjC,CAAvB;;;;MAII9H,SAAS2B,cAAcC,UAAd,EAA0BC,OAAOiG,IAAjC,EAAuCjG,MAAvC,CAAb;MACIoG,UAAUjI,SAASuH,aAAvB;MACIW,iBAAiBV,cAAcrF,IAAIN,OAAOC,KAAX,CAAd,GAAkC,CAAvD;;;MAGG0F,eAAe7F,cAAcC,UAAd,EAA0B,CAA1B,EAA6BC,MAA7B,KAAwC0F,aAA1D,EAAyE;WAChEO,IAAP,GAAc,CAAd;GADF,MAEO,IAAGN,eAAeU,iBAAiBrG,OAAOiG,IAAvC,IAA+CnG,cAAcC,UAAd,EAA0BsG,cAA1B,EAA0CrG,MAA1C,KAAqD0F,aAAvG,EAAsH;;;;WAIpHO,IAAP,GAAcI,cAAd;GAJK,MAKA;;WAEE,IAAP,EAAa;UACPD,WAAWtG,cAAcC,UAAd,EAA0BC,OAAOiG,IAAjC,EAAuCjG,MAAvC,KAAkD0F,aAAjE,EAAgF;eACvEO,IAAP,IAAe,CAAf;OADF,MAEO,IAAI,CAACG,OAAD,IAAYtG,cAAcC,UAAd,EAA0BC,OAAOiG,IAAP,GAAc,CAAxC,EAA2CjG,MAA3C,KAAsD0F,aAAtE,EAAqF;eACnFO,IAAP,IAAe,CAAf;YACGN,eAAe3F,OAAOiG,IAAP,GAAc,CAAd,KAAoB,CAAtC,EAAyC;iBAChCA,IAAP,IAAe,CAAf;;;OAHG,MAMA;;;;UAIJL,wBAAwB,IAA3B,EAAiC;cACzB,IAAIU,KAAJ,CAAU,oEAAV,CAAN;;;;;MAKFC,UAAU,SAAd;SACON,IAAP,GAAc/G,KAAKC,GAAL,CAASa,OAAOiG,IAAhB,EAAsBM,OAAtB,CAAd;WACSC,aAAT,CAAuBtJ,KAAvB,EAA8BuJ,SAA9B,EAAyC;;QAEnCvJ,WAAWA,SAASuJ,SAApB,CAAJ,EAAoC;eACxB,KAAKA,YAAY,CAAZ,GAAgBF,OAAhB,GAA0B,CAACA,OAAhC,CAAV;;WAEKrJ,KAAP;;;;WAIO8C,OAAOwF,GAAhB;WACSxF,OAAOb,GAAhB;SACO0G,SAAS7F,OAAOiG,IAAhB,IAAwBjG,OAAOmF,GAAtC,EAA2C;aAChCqB,cAAcX,MAAd,EAAsB7F,OAAOiG,IAA7B,CAAT;;SAEKH,SAAS9F,OAAOiG,IAAhB,IAAwBjG,OAAOgF,IAAtC,EAA4C;aACjCwB,cAAcV,MAAd,EAAsB,CAAC9F,OAAOiG,IAA9B,CAAT;;SAEKT,GAAP,GAAaK,MAAb;SACO1G,GAAP,GAAa2G,MAAb;SACO7F,KAAP,GAAeD,OAAOb,GAAP,GAAaa,OAAOwF,GAAnC;;MAEIkB,SAAS,EAAb;OACKhF,IAAI1B,OAAOwF,GAAhB,EAAqB9D,KAAK1B,OAAOb,GAAjC,EAAsCuC,IAAI8E,cAAc9E,CAAd,EAAiB1B,OAAOiG,IAAxB,CAA1C,EAAyE;QACnE/I,QAAQgD,mBAAmBwB,CAAnB,CAAZ;QACIxE,UAAUwJ,OAAOA,OAAOvI,MAAP,GAAgB,CAAvB,CAAd,EAAyC;aAChCkF,IAAP,CAAY3B,CAAZ;;;SAGGgF,MAAP,GAAgBA,MAAhB;SACO1G,MAAP;;;ACheF,uBAAgB,UAAU2G,QAAV,EAAoBC,WAApB,EAAiC;MAC3C,EAAED,oBAAoBC,WAAtB,CAAJ,EAAwC;UAChC,IAAIC,SAAJ,CAAc,mCAAd,CAAN;;CAFJ;;ACAA,mBAAe,CAAC,YAAY;WACjBC,gBAAT,CAA0BrF,MAA1B,EAAkCsF,KAAlC,EAAyC;SAClC,IAAIrF,IAAI,CAAb,EAAgBA,IAAIqF,MAAM5I,MAA1B,EAAkCuD,GAAlC,EAAuC;UACjCsF,aAAaD,MAAMrF,CAAN,CAAjB;iBACWuF,UAAX,GAAwBD,WAAWC,UAAX,IAAyB,KAAjD;iBACWC,YAAX,GAA0B,IAA1B;UACI,WAAWF,UAAf,EAA2BA,WAAWG,QAAX,GAAsB,IAAtB;aACpBC,cAAP,CAAsB3F,MAAtB,EAA8BuF,WAAW1E,GAAzC,EAA8C0E,UAA9C;;;;SAIG,UAAUJ,WAAV,EAAuBS,UAAvB,EAAmCC,WAAnC,EAAgD;QACjDD,UAAJ,EAAgBP,iBAAiBF,YAAYxD,SAA7B,EAAwCiE,UAAxC;QACZC,WAAJ,EAAiBR,iBAAiBF,WAAjB,EAA8BU,WAA9B;WACVV,WAAP;GAHF;CAXa,GAAf;;ACEA;;;;;;;;AAQA,IAAaW,OAAb,GACE,iBAAYC,QAAZ,EAAsB;;;MAChBC,OAAO,IAAX;;OAEKC,WAAL,GAAmB,EAAnB;OACI,IAAIhG,IAAI,CAAZ,EAAeA,IAAI8F,SAASrJ,MAA5B,EAAoCuD,GAApC,EAAyC;SAClCgG,WAAL,CAAiBrE,IAAjB,CAAsB,IAAIsE,GAAJ,CAAQH,SAAS9F,CAAT,CAAR,CAAtB;;;;SAIKU,IAAP,CAAYuF,IAAIvE,SAAhB,EAA2BwE,MAA3B,CAAkC,UAASC,iBAAT,EAA4B;WACrD,CAAC,aAAD,EACH,QADG,EAEH,eAFG,EAGH,kBAHG,EAIH,SAJG,EAKH,QALG,EAMH,SANG,EAOH,QAPG,EAQH,OARG,EAQMC,OARN,CAQcD,iBARd,MAQqC,CAAC,CAR7C;GADF,EAUGvI,OAVH,CAUW,UAASuI,iBAAT,EAA4B;SAChCA,iBAAL,IAA0B,YAAW;UAC/BrI,OAAOpB,MAAMgF,SAAN,CAAgBD,KAAhB,CAAsB4E,IAAtB,CAA2BlG,SAA3B,EAAsC,CAAtC,CAAX;WACK6F,WAAL,CAAiBpI,OAAjB,CAAyB,UAAS0I,OAAT,EAAkB;YACrC5E,SAAJ,CAAcyE,iBAAd,EAAiCxJ,KAAjC,CAAuC2J,OAAvC,EAAgDxI,IAAhD;OADF;aAGOiI,IAAP;KALF;GAXF;CAVJ;;ACPA;;;;;;;;;;;AAWA,IAAaE,GAAb;eAEcxD,IAAZ,EAAkB8D,UAAlB,EAA8BC,SAA9B,EAAyCC,MAAzC,EAAiDC,WAAjD,EAA8D;;;;QAEzDjE,gBAAgBkE,OAAnB,EAA4B;WACrBC,KAAL,GAAanE,IAAb;KADF,MAEO;WACAmE,KAAL,GAAa1L,SAAS2L,eAAT,CAAyBvM,WAAWwM,GAApC,EAAyCrE,IAAzC,CAAb;;;UAGGA,SAAS,KAAZ,EAAmB;aACZsE,IAAL,CAAU;sBACIzM,WAAW0M;SADzB;;;;QAMDT,UAAH,EAAe;WACRQ,IAAL,CAAUR,UAAV;;;QAGCC,SAAH,EAAc;WACPS,QAAL,CAAcT,SAAd;;;QAGCC,MAAH,EAAW;UACLC,eAAeD,OAAOG,KAAP,CAAaM,UAAhC,EAA4C;eACnCN,KAAP,CAAaO,YAAb,CAA0B,KAAKP,KAA/B,EAAsCH,OAAOG,KAAP,CAAaM,UAAnD;OADF,MAEO;eACEN,KAAP,CAAaQ,WAAb,CAAyB,KAAKR,KAA9B;;;;;;;;;;;;;;;;;yBAaDL,UA1CP,EA0CmBc,EA1CnB,EA0CuB;UAChB,OAAOd,UAAP,KAAsB,QAAzB,EAAmC;YAC9Bc,EAAH,EAAO;iBACE,KAAKT,KAAL,CAAWU,cAAX,CAA0BD,EAA1B,EAA8Bd,UAA9B,CAAP;SADF,MAEO;iBACE,KAAKK,KAAL,CAAWW,YAAX,CAAwBhB,UAAxB,CAAP;;;;aAIG7F,IAAP,CAAY6F,UAAZ,EAAwB3I,OAAxB,CAAgC,UAASgD,GAAT,EAAc;;YAEzC2F,WAAW3F,GAAX,MAAoBhF,SAAvB,EAAkC;;;;YAI9BgF,IAAIwF,OAAJ,CAAY,GAAZ,MAAqB,CAAC,CAA1B,EAA6B;cACvBoB,sBAAsB5G,IAAI6G,KAAJ,CAAU,GAAV,CAA1B;eACKb,KAAL,CAAWc,cAAX,CAA0BpN,WAAWkN,oBAAoB,CAApB,CAAX,CAA1B,EAA8D5G,GAA9D,EAAmE2F,WAAW3F,GAAX,CAAnE;SAFF,MAGO;eACAgG,KAAL,CAAWe,YAAX,CAAwB/G,GAAxB,EAA6B2F,WAAW3F,GAAX,CAA7B;;OAV4B,CAY9BgH,IAZ8B,CAYzB,IAZyB,CAAhC;;aAcO,IAAP;;;;;;;;;;;;;;;;yBAaGnF,IA9EP,EA8Ea8D,UA9Eb,EA8EyBC,SA9EzB,EA8EoCE,WA9EpC,EA8EiD;aACtC,IAAIT,GAAJ,CAAQxD,IAAR,EAAc8D,UAAd,EAA0BC,SAA1B,EAAqC,IAArC,EAA2CE,WAA3C,CAAP;;;;;;;;;;;;6BASO;aACA,KAAKE,KAAL,CAAWiB,UAAX,YAAiCC,UAAjC,GAA8C,IAAI7B,GAAJ,CAAQ,KAAKW,KAAL,CAAWiB,UAAnB,CAA9C,GAA+E,IAAtF;;;;;;;;;;;;2BASK;UACDE,OAAO,KAAKnB,KAAhB;aACMmB,KAAKC,QAAL,KAAkB,KAAxB,EAA+B;eACtBD,KAAKF,UAAZ;;aAEK,IAAI5B,GAAJ,CAAQ8B,IAAR,CAAP;;;;;;;;;;;;;kCAUYE,QAjHhB,EAiH0B;UAClBC,YAAY,KAAKtB,KAAL,CAAW7L,aAAX,CAAyBkN,QAAzB,CAAhB;aACOC,YAAY,IAAIjC,GAAJ,CAAQiC,SAAR,CAAZ,GAAiC,IAAxC;;;;;;;;;;;;;qCAUeD,QA7HnB,EA6H6B;UACrBE,aAAa,KAAKvB,KAAL,CAAWwB,gBAAX,CAA4BH,QAA5B,CAAjB;aACOE,WAAW1L,MAAX,GAAoB,IAAIoJ,OAAJ,CAAYsC,UAAZ,CAApB,GAA8C,IAArD;;;;;;;;;;;;8BASQ;aACD,KAAKvB,KAAZ;;;;;;;;;;;;;;;;kCAaYyB,OAtJhB,EAsJyB9B,UAtJzB,EAsJqCC,SAtJrC,EAsJgDE,WAtJhD,EAsJ6D;;;UAGtD,OAAO2B,OAAP,KAAmB,QAAtB,EAAgC;YAC1BC,YAAYpN,SAASqN,aAAT,CAAuB,KAAvB,CAAhB;kBACUC,SAAV,GAAsBH,OAAtB;kBACUC,UAAUpB,UAApB;;;;cAIMS,YAAR,CAAqB,OAArB,EAA8BrN,WAAWmO,KAAzC;;;;UAIIC,QAAQ,KAAKC,IAAL,CAAU,eAAV,EAA2BpC,UAA3B,EAAuCC,SAAvC,EAAkDE,WAAlD,CAAZ;;;YAGME,KAAN,CAAYQ,WAAZ,CAAwBiB,OAAxB;;aAEOK,KAAP;;;;;;;;;;;;;yBAUGE,CAnLP,EAmLU;WACDhC,KAAL,CAAWQ,WAAX,CAAuBlM,SAAS2N,cAAT,CAAwBD,CAAxB,CAAvB;aACO,IAAP;;;;;;;;;;;;4BASM;aACC,KAAKhC,KAAL,CAAWM,UAAlB,EAA8B;aACvBN,KAAL,CAAWkC,WAAX,CAAuB,KAAKlC,KAAL,CAAWM,UAAlC;;;aAGK,IAAP;;;;;;;;;;;;6BASO;WACFN,KAAL,CAAWiB,UAAX,CAAsBiB,WAAtB,CAAkC,KAAKlC,KAAvC;aACO,KAAKH,MAAL,EAAP;;;;;;;;;;;;;4BAUMsC,UAxNV,EAwNsB;WACbnC,KAAL,CAAWiB,UAAX,CAAsBmB,YAAtB,CAAmCD,WAAWnC,KAA9C,EAAqD,KAAKA,KAA1D;aACOmC,UAAP;;;;;;;;;;;;;;2BAWKzC,OArOT,EAqOkBI,WArOlB,EAqO+B;UACxBA,eAAe,KAAKE,KAAL,CAAWM,UAA7B,EAAyC;aAClCN,KAAL,CAAWO,YAAX,CAAwBb,QAAQM,KAAhC,EAAuC,KAAKA,KAAL,CAAWM,UAAlD;OADF,MAEO;aACAN,KAAL,CAAWQ,WAAX,CAAuBd,QAAQM,KAA/B;;;aAGK,IAAP;;;;;;;;;;;;8BASQ;aACD,KAAKA,KAAL,CAAWW,YAAX,CAAwB,OAAxB,IAAmC,KAAKX,KAAL,CAAWW,YAAX,CAAwB,OAAxB,EAAiC0B,IAAjC,GAAwCxB,KAAxC,CAA8C,KAA9C,CAAnC,GAA0F,EAAjG;;;;;;;;;;;;;6BAUOyB,KAhQX,EAgQkB;WACTtC,KAAL,CAAWe,YAAX,CAAwB,OAAxB,EACE,KAAKwB,OAAL,GACGC,MADH,CACUF,MAAMD,IAAN,GAAaxB,KAAb,CAAmB,KAAnB,CADV,EAEGvB,MAFH,CAEU,UAASyC,IAAT,EAAeU,GAAf,EAAoBC,IAApB,EAA0B;eACzBA,KAAKlD,OAAL,CAAauC,IAAb,MAAuBU,GAA9B;OAHJ,EAIKE,IAJL,CAIU,GAJV,CADF;;aAQO,IAAP;;;;;;;;;;;;;gCAUUL,KAnRd,EAmRqB;UACbM,iBAAiBN,MAAMD,IAAN,GAAaxB,KAAb,CAAmB,KAAnB,CAArB;;WAEKb,KAAL,CAAWe,YAAX,CAAwB,OAAxB,EAAiC,KAAKwB,OAAL,GAAejD,MAAf,CAAsB,UAASzD,IAAT,EAAe;eAC7D+G,eAAepD,OAAf,CAAuB3D,IAAvB,MAAiC,CAAC,CAAzC;OAD+B,EAE9B8G,IAF8B,CAEzB,GAFyB,CAAjC;;aAIO,IAAP;;;;;;;;;;;;uCASiB;WACZ3C,KAAL,CAAWe,YAAX,CAAwB,OAAxB,EAAiC,EAAjC;aACO,IAAP;;;;;;;;;;;;6BASO;aACA,KAAKf,KAAL,CAAW6C,qBAAX,GAAmCC,MAA1C;;;;;;;;;;;;4BASM;aACC,KAAK9C,KAAL,CAAW6C,qBAAX,GAAmCE,KAA1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA4CMC,UArWV,EAqWsBC,MArWtB,EAqW8BC,YArW9B,EAqW4C;UACrCD,WAAWjO,SAAd,EAAyB;iBACd,IAAT;;;aAGK8E,IAAP,CAAYkJ,UAAZ,EAAwBhM,OAAxB,CAAgC,SAASmM,0BAAT,CAAoCC,SAApC,EAA+C;;iBAEpEC,aAAT,CAAuBC,mBAAvB,EAA4CL,MAA5C,EAAoD;cAC9CM,sBAAsB,EAA1B;cACEC,OADF;cAEEC,OAFF;cAGEC,eAHF;;;;cAOGJ,oBAAoBK,MAAvB,EAA+B;;8BAEXL,oBAAoBK,MAApB,YAAsC7N,KAAtC,GAChBwN,oBAAoBK,MADJ,GAEhBC,QAAQN,oBAAoBK,MAA5B,CAFF;mBAGOL,oBAAoBK,MAA3B;;;;8BAIkBE,KAApB,GAA4B5O,WAAWqO,oBAAoBO,KAA/B,EAAsC,IAAtC,CAA5B;8BACoBC,GAApB,GAA0B7O,WAAWqO,oBAAoBQ,GAA/B,EAAoC,IAApC,CAA1B;;cAEGJ,eAAH,EAAoB;gCACEK,QAApB,GAA+B,QAA/B;gCACoBC,UAApB,GAAiCN,gBAAgBf,IAAhB,CAAqB,GAArB,CAAjC;gCACoBsB,QAApB,GAA+B,KAA/B;;;;cAIChB,MAAH,EAAW;gCACWiB,IAApB,GAA2B,QAA3B;;gCAEoBd,SAApB,IAAiCE,oBAAoBa,IAArD;iBACKhE,IAAL,CAAUoD,mBAAV;;;;sBAIUpO,SAASmO,oBAAoBO,KAApB,IAA6B,CAAtC,EAAyCjP,KAAnD;gCACoBiP,KAApB,GAA4B,YAA5B;;;oBAGQ,KAAK9B,IAAL,CAAU,SAAV,EAAqB7I,OAAO;2BACrBkK;WADc,EAE5BE,mBAF4B,CAArB,CAAV;;cAIGL,MAAH,EAAW;;uBAEE,YAAW;;;;kBAIhB;wBACMjD,KAAR,CAAcoE,YAAd;eADF,CAEE,OAAMC,GAAN,EAAW;;oCAESjB,SAApB,IAAiCE,oBAAoBgB,EAArD;qBACKnE,IAAL,CAAUoD,mBAAV;;wBAEQgB,MAAR;;aAXO,CAaTvD,IAbS,CAaJ,IAbI,CAAX,EAacyC,OAbd;;;cAgBCP,YAAH,EAAiB;oBACPlD,KAAR,CAAcwE,gBAAd,CAA+B,YAA/B,EAA6C,SAASC,gBAAT,GAA4B;2BAC1DC,IAAb,CAAkB,gBAAlB,EAAoC;yBACzB,IADyB;yBAEzBlB,QAAQxD,KAFiB;wBAG1BsD;eAHV;aAD2C,CAM3CtC,IAN2C,CAMtC,IANsC,CAA7C;;;kBASMhB,KAAR,CAAcwE,gBAAd,CAA+B,UAA/B,EAA2C,SAASG,cAAT,GAA0B;gBAChEzB,YAAH,EAAiB;2BACFwB,IAAb,CAAkB,cAAlB,EAAkC;yBACvB,IADuB;yBAEvBlB,QAAQxD,KAFe;wBAGxBsD;eAHV;;;gBAOCL,MAAH,EAAW;;kCAEWG,SAApB,IAAiCE,oBAAoBgB,EAArD;mBACKnE,IAAL,CAAUoD,mBAAV;;sBAEQgB,MAAR;;WAduC,CAgBzCvD,IAhByC,CAgBpC,IAhBoC,CAA3C;;;;YAoBCgC,WAAWI,SAAX,aAAiCtN,KAApC,EAA2C;qBAC9BsN,SAAX,EAAsBpM,OAAtB,CAA8B,UAASsM,mBAAT,EAA8B;0BAC5CtC,IAAd,CAAmB,IAAnB,EAAyBsC,mBAAzB,EAA8C,KAA9C;WAD4B,CAE5BtC,IAF4B,CAEvB,IAFuB,CAA9B;SADF,MAIO;wBACSA,IAAd,CAAmB,IAAnB,EAAyBgC,WAAWI,SAAX,CAAzB,EAAgDH,MAAhD;;OAlG4B,CAqG9BjC,IArG8B,CAqGzB,IArGyB,CAAhC;;aAuGO,IAAP;;;;;;;;;;;;;;AAWJ,AAAO,SAAS4D,WAAT,CAAqBC,OAArB,EAA8B;SAC5BvQ,SAASwQ,cAAT,CAAwBC,UAAxB,CAAmC,wCAAwCF,OAA3E,EAAoF,KAApF,CAAP;;;;;;;;AAQF,AAAO,IAAMjB,UAAU;cACT,CAAC,IAAD,EAAO,CAAP,EAAU,KAAV,EAAiB,KAAjB,CADS;eAER,CAAC,IAAD,EAAO,KAAP,EAAc,KAAd,EAAqB,CAArB,CAFQ;iBAGN,CAAC,KAAD,EAAQ,IAAR,EAAc,IAAd,EAAoB,IAApB,CAHM;cAIT,CAAC,IAAD,EAAO,KAAP,EAAc,IAAd,EAAoB,IAApB,CAJS;eAKR,CAAC,IAAD,EAAO,IAAP,EAAa,IAAb,EAAmB,IAAnB,CALQ;iBAMN,CAAC,KAAD,EAAQ,IAAR,EAAc,KAAd,EAAqB,KAArB,CANM;eAOR,CAAC,IAAD,EAAO,KAAP,EAAc,KAAd,EAAqB,IAArB,CAPQ;gBAQP,CAAC,KAAD,EAAQ,IAAR,EAAc,KAAd,EAAqB,CAArB,CARO;kBASL,CAAC,KAAD,EAAQ,KAAR,EAAe,KAAf,EAAsB,CAAtB,CATK;eAUR,CAAC,KAAD,EAAQ,IAAR,EAAc,KAAd,EAAqB,IAArB,CAVQ;gBAWP,CAAC,KAAD,EAAQ,IAAR,EAAc,IAAd,EAAoB,CAApB,CAXO;kBAYL,CAAC,IAAD,EAAO,CAAP,EAAU,KAAV,EAAiB,CAAjB,CAZK;eAaR,CAAC,KAAD,EAAQ,IAAR,EAAc,KAAd,EAAqB,IAArB,CAbQ;gBAcP,CAAC,IAAD,EAAO,CAAP,EAAU,IAAV,EAAgB,CAAhB,CAdO;kBAeL,CAAC,IAAD,EAAO,CAAP,EAAU,IAAV,EAAgB,CAAhB,CAfK;cAgBT,CAAC,IAAD,EAAO,IAAP,EAAa,KAAb,EAAoB,KAApB,CAhBS;eAiBR,CAAC,IAAD,EAAO,CAAP,EAAU,IAAV,EAAgB,CAAhB,CAjBQ;iBAkBN,CAAC,CAAD,EAAI,CAAJ,EAAO,CAAP,EAAU,CAAV,CAlBM;cAmBT,CAAC,GAAD,EAAM,IAAN,EAAY,IAAZ,EAAkB,KAAlB,CAnBS;eAoBR,CAAC,KAAD,EAAQ,IAAR,EAAc,KAAd,EAAqB,CAArB,CApBQ;iBAqBN,CAAC,KAAD,EAAQ,KAAR,EAAe,IAAf,EAAqB,IAArB,CArBM;cAsBT,CAAC,GAAD,EAAM,CAAC,IAAP,EAAa,KAAb,EAAoB,KAApB,CAtBS;eAuBR,CAAC,KAAD,EAAQ,KAAR,EAAe,IAAf,EAAqB,KAArB,CAvBQ;iBAwBN,CAAC,IAAD,EAAO,CAAC,IAAR,EAAc,KAAd,EAAqB,IAArB;CAxBV;;AC9eP;;;;;;;;;;AAUA,AAAO,SAASoB,SAAT,CAAmBtD,SAAnB,EAA8BqB,KAA9B,EAAqCD,MAArC,EAA6ClD,SAA7C,EAAwD;MACzDM,GAAJ;;UAEQ6C,SAAS,MAAjB;WACSD,UAAU,MAAnB;;;;QAIMhI,SAAN,CAAgBD,KAAhB,CAAsB4E,IAAtB,CAA2BiC,UAAUF,gBAAV,CAA2B,KAA3B,CAA3B,EAA8DlC,MAA9D,CAAqE,SAAS2F,wBAAT,CAAkC/E,GAAlC,EAAuC;WACnGA,IAAIQ,cAAJ,CAAmBhN,WAAWmO,KAA9B,EAAqC,IAArC,CAAP;GADF,EAEG7K,OAFH,CAEW,SAASkO,qBAAT,CAA+BhF,GAA/B,EAAoC;cACnCgC,WAAV,CAAsBhC,GAAtB;GAHF;;;QAOM,IAAIb,GAAJ,CAAQ,KAAR,EAAec,IAAf,CAAoB;WACjB4C,KADiB;YAEhBD;GAFJ,EAGHzC,QAHG,CAGMT,SAHN,EAGiBO,IAHjB,CAGsB;WACnB,YAAY4C,KAAZ,GAAoB,YAApB,GAAmCD,MAAnC,GAA4C;GAJ/C,CAAN;;;YAQUtC,WAAV,CAAsBN,IAAIF,KAA1B;;SAEOE,GAAP;;;;;;;;;;;AAWF,AAAO,SAASiF,gBAAT,CAA0BC,OAA1B,EAAmCC,QAAnC,EAA6C;aACvCA,YAAY,CAAvB;;SAEO,OAAOD,OAAP,KAAmB,QAAnB,GAA8B;SAC9BA,OAD8B;WAE5BA,OAF4B;YAG3BA,OAH2B;UAI7BA;GAJD,GAKH;SACG,OAAOA,QAAQE,GAAf,KAAuB,QAAvB,GAAkCF,QAAQE,GAA1C,GAAgDD,QADnD;WAEK,OAAOD,QAAQG,KAAf,KAAyB,QAAzB,GAAoCH,QAAQG,KAA5C,GAAoDF,QAFzD;YAGM,OAAOD,QAAQI,MAAf,KAA0B,QAA1B,GAAqCJ,QAAQI,MAA7C,GAAsDH,QAH5D;UAII,OAAOD,QAAQK,IAAf,KAAwB,QAAxB,GAAmCL,QAAQK,IAA3C,GAAkDJ;GAT1D;;;;;;;;;;;;AAsBF,AAAO,SAASK,eAAT,CAAyBxF,GAAzB,EAA8BtE,OAA9B,EAAuC+J,eAAvC,EAAwD;MACzDC,UAAU,CAAC,EAAEhK,QAAQiK,KAAR,IAAiBjK,QAAQkK,KAA3B,CAAf;MACIC,cAAcH,UAAUhK,QAAQkK,KAAR,CAAcE,MAAxB,GAAiC,CAAnD;MACIC,cAAcL,UAAUhK,QAAQiK,KAAR,CAAcG,MAAxB,GAAiC,CAAnD;;MAEIjD,QAAQ7C,IAAI6C,KAAJ,MAAe5N,SAASyG,QAAQmH,KAAjB,EAAwBnO,KAAvC,IAAgD,CAA5D;MACIkO,SAAS5C,IAAI4C,MAAJ,MAAgB3N,SAASyG,QAAQkH,MAAjB,EAAyBlO,KAAzC,IAAkD,CAA/D;MACIsR,oBAAoBf,iBAAiBvJ,QAAQuK,YAAzB,EAAuCR,eAAvC,CAAxB;;;UAGQ/O,KAAKC,GAAL,CAASkM,KAAT,EAAgBgD,cAAcG,kBAAkBT,IAAhC,GAAuCS,kBAAkBX,KAAzE,CAAR;WACS3O,KAAKC,GAAL,CAASiM,MAAT,EAAiBmD,cAAcC,kBAAkBZ,GAAhC,GAAsCY,kBAAkBV,MAAzE,CAAT;;MAEIY,YAAY;aACLF,iBADK;WAEP,iBAAY;aACV,KAAK3N,EAAL,GAAU,KAAKD,EAAtB;KAHY;YAKN,kBAAY;aACX,KAAK+N,EAAL,GAAU,KAAKC,EAAtB;;GANJ;;MAUGV,OAAH,EAAY;QACNhK,QAAQiK,KAAR,CAAcU,QAAd,KAA2B,OAA/B,EAAwC;gBAC5BD,EAAV,GAAeJ,kBAAkBZ,GAAlB,GAAwBW,WAAvC;gBACUI,EAAV,GAAezP,KAAKC,GAAL,CAASiM,SAASoD,kBAAkBV,MAApC,EAA4CY,UAAUE,EAAV,GAAe,CAA3D,CAAf;KAFF,MAGO;gBACKA,EAAV,GAAeJ,kBAAkBZ,GAAjC;gBACUe,EAAV,GAAezP,KAAKC,GAAL,CAASiM,SAASoD,kBAAkBV,MAA3B,GAAoCS,WAA7C,EAA0DG,UAAUE,EAAV,GAAe,CAAzE,CAAf;;;QAGE1K,QAAQkK,KAAR,CAAcS,QAAd,KAA2B,OAA/B,EAAwC;gBAC5BjO,EAAV,GAAe4N,kBAAkBT,IAAlB,GAAyBM,WAAxC;gBACUxN,EAAV,GAAe3B,KAAKC,GAAL,CAASkM,QAAQmD,kBAAkBX,KAAnC,EAA0Ca,UAAU9N,EAAV,GAAe,CAAzD,CAAf;KAFF,MAGO;gBACKA,EAAV,GAAe4N,kBAAkBT,IAAjC;gBACUlN,EAAV,GAAe3B,KAAKC,GAAL,CAASkM,QAAQmD,kBAAkBX,KAA1B,GAAkCQ,WAA3C,EAAwDK,UAAU9N,EAAV,GAAe,CAAvE,CAAf;;GAdJ,MAgBO;cACKA,EAAV,GAAe4N,kBAAkBT,IAAjC;cACUlN,EAAV,GAAe3B,KAAKC,GAAL,CAASkM,QAAQmD,kBAAkBX,KAAnC,EAA0Ca,UAAU9N,EAAV,GAAe,CAAzD,CAAf;cACUgO,EAAV,GAAeJ,kBAAkBZ,GAAjC;cACUe,EAAV,GAAezP,KAAKC,GAAL,CAASiM,SAASoD,kBAAkBV,MAApC,EAA4CY,UAAUE,EAAV,GAAe,CAA3D,CAAf;;;SAGKF,SAAP;;;;;;;;;;;;;;;;AAgBF,AAAO,SAASI,UAAT,CAAoBD,QAApB,EAA8BtP,KAA9B,EAAqCwP,IAArC,EAA2CT,MAA3C,EAAmDnQ,MAAnD,EAA2D6Q,KAA3D,EAAkEnE,OAAlE,EAA2EW,YAA3E,EAAyF;MAC1FyD,iBAAiB,EAArB;iBACeF,KAAKG,KAAL,CAAWnE,GAAX,GAAiB,GAAhC,IAAuC8D,QAAvC;iBACeE,KAAKG,KAAL,CAAWnE,GAAX,GAAiB,GAAhC,IAAuC8D,QAAvC;iBACeE,KAAKI,YAAL,CAAkBpE,GAAlB,GAAwB,GAAvC,IAA8CuD,MAA9C;iBACeS,KAAKI,YAAL,CAAkBpE,GAAlB,GAAwB,GAAvC,IAA8CuD,SAASnQ,MAAvD;;MAEIiR,cAAcJ,MAAM3E,IAAN,CAAW,MAAX,EAAmB4E,cAAnB,EAAmCpE,QAAQI,IAAR,CAAa,GAAb,CAAnC,CAAlB;;;eAGa+B,IAAb,CAAkB,MAAlB,EACExL,OAAO;UACC,MADD;UAECuN,IAFD;WAGExP,KAHF;WAIEyP,KAJF;aAKII;GALX,EAMGH,cANH,CADF;;;;;;;;;;;;AAoBF,AAAO,SAASI,oBAAT,CAA8BC,SAA9B,EAAyCZ,SAAzC,EAAoDxG,SAApD,EAA+DsD,YAA/D,EAA6E;MAC9E+D,iBAAiBD,UAAUjF,IAAV,CAAe,MAAf,EAAuB;OACvCqE,UAAU9N,EAD6B;OAEvC8N,UAAUE,EAF6B;WAGnCF,UAAUrD,KAAV,EAHmC;YAIlCqD,UAAUtD,MAAV;GAJW,EAKlBlD,SALkB,EAKP,IALO,CAArB;;;eAQa8E,IAAb,CAAkB,MAAlB,EAA0B;UAClB,gBADkB;WAEjBsC,SAFiB;aAGfC;GAHX;;;;;;;;;;;;;;;;;;;AAuBF,AAAO,SAASC,WAAT,CAAqBX,QAArB,EAA+B1Q,MAA/B,EAAuCoB,KAAvC,EAA8C2D,MAA9C,EAAsD6L,IAAtD,EAA4DU,UAA5D,EAAwEC,WAAxE,EAAqFV,KAArF,EAA4FnE,OAA5F,EAAqG8E,gBAArG,EAAuHnE,YAAvH,EAAqI;MACtIoE,YAAJ;MACIX,iBAAiB,EAArB;;iBAEeF,KAAKG,KAAL,CAAWnE,GAA1B,IAAiC8D,WAAWa,YAAYX,KAAKG,KAAL,CAAWnE,GAAvB,CAA5C;iBACegE,KAAKI,YAAL,CAAkBpE,GAAjC,IAAwC2E,YAAYX,KAAKI,YAAL,CAAkBpE,GAA9B,CAAxC;iBACegE,KAAKG,KAAL,CAAWW,GAA1B,IAAiC1R,MAAjC;iBACe4Q,KAAKI,YAAL,CAAkBU,GAAjC,IAAwC3Q,KAAKC,GAAL,CAAS,CAAT,EAAYsQ,aAAa,EAAzB,CAAxC;;MAEGE,gBAAH,EAAqB;;;QAGf5F,UAAU,kBAAkBc,QAAQI,IAAR,CAAa,GAAb,CAAlB,GAAsC,WAAtC,GACZ8D,KAAKG,KAAL,CAAWW,GADC,GACK,IADL,GACY3Q,KAAKmB,KAAL,CAAW4O,eAAeF,KAAKG,KAAL,CAAWW,GAA1B,CAAX,CADZ,GACyD,MADzD,GAEZd,KAAKI,YAAL,CAAkBU,GAFN,GAEY,IAFZ,GAEmB3Q,KAAKmB,KAAL,CAAW4O,eAAeF,KAAKI,YAAL,CAAkBU,GAAjC,CAAX,CAFnB,GAEuE,MAFvE,GAGZ3M,OAAO3D,KAAP,CAHY,GAGI,SAHlB;;mBAKeyP,MAAMc,aAAN,CAAoB/F,OAApB,EAA6BvI,OAAO;aAC1C;KADmC,EAEzCyN,cAFyC,CAA7B,CAAf;GARF,MAWO;mBACUD,MAAM3E,IAAN,CAAW,MAAX,EAAmB4E,cAAnB,EAAmCpE,QAAQI,IAAR,CAAa,GAAb,CAAnC,EAAsD8E,IAAtD,CAA2D7M,OAAO3D,KAAP,CAA3D,CAAf;;;eAGWyN,IAAb,CAAkB,MAAlB,EAA0BxL,OAAO;UACzB,OADyB;UAEzBuN,IAFyB;WAGxBxP,KAHwB;WAIxByP,KAJwB;aAKtBY,YALsB;UAMzB1M,OAAO3D,KAAP;GANkB,EAOvB0P,cAPuB,CAA1B;;;AC9NF;;;;;;;;;AASA,AAAO,SAASe,eAAT,CAAyB9L,OAAzB,EAAkC+L,iBAAlC,EAAqDzE,YAArD,EAAmE;MACpE0E,cAAc1O,OAAO,EAAP,EAAW0C,OAAX,CAAlB;MACEiM,cADF;MAEEC,sBAAsB,EAFxB;MAGE1O,CAHF;;WAKS2O,oBAAT,CAA8BC,UAA9B,EAA0C;QACpCC,kBAAkBJ,cAAtB;qBACiB3O,OAAO,EAAP,EAAW0O,WAAX,CAAjB;;QAEID,iBAAJ,EAAuB;WAChBvO,IAAI,CAAT,EAAYA,IAAIuO,kBAAkB9R,MAAlC,EAA0CuD,GAA1C,EAA+C;YACzC8O,MAAMC,OAAOC,UAAP,CAAkBT,kBAAkBvO,CAAlB,EAAqB,CAArB,CAAlB,CAAV;YACI8O,IAAIG,OAAR,EAAiB;2BACEnP,OAAO2O,cAAP,EAAuBF,kBAAkBvO,CAAlB,EAAqB,CAArB,CAAvB,CAAjB;;;;;QAKH8J,gBAAgB8E,UAAnB,EAA+B;mBAChBtD,IAAb,CAAkB,gBAAlB,EAAoC;yBACjBuD,eADiB;wBAElBJ;OAFlB;;;;WAOKS,yBAAT,GAAqC;wBACftR,OAApB,CAA4B,UAASkR,GAAT,EAAc;UACpCK,cAAJ,CAAmBR,oBAAnB;KADF;;;MAKE,CAACI,OAAOC,UAAZ,EAAwB;UAChB,kEAAN;GADF,MAEO,IAAIT,iBAAJ,EAAuB;;SAEvBvO,IAAI,CAAT,EAAYA,IAAIuO,kBAAkB9R,MAAlC,EAA0CuD,GAA1C,EAA+C;UACzC8O,MAAMC,OAAOC,UAAP,CAAkBT,kBAAkBvO,CAAlB,EAAqB,CAArB,CAAlB,CAAV;UACIoP,WAAJ,CAAgBT,oBAAhB;0BACoBhN,IAApB,CAAyBmN,GAAzB;;;;;;SAMG;+BACsBI,yBADtB;uBAEc,SAASG,iBAAT,GAA6B;aACvCvP,OAAO,EAAP,EAAW2O,cAAX,CAAP;;GAHJ;;;ICzDWa,YAAb;0BACgB;;;SACPC,QAAL,GAAgB,EAAhB;;;;;;;;;;;;;;oCAUcC,KAZlB,EAYyBC,OAZzB,EAYkC;WACzBF,QAAL,CAAcC,KAAd,IAAuB,KAAKD,QAAL,CAAcC,KAAd,KAAwB,EAA/C;WACKD,QAAL,CAAcC,KAAd,EAAqB7N,IAArB,CAA0B8N,OAA1B;;;;;;;;;;;;;uCAUiBD,KAxBrB,EAwB4BC,OAxB5B,EAwBqC;;UAE9B,KAAKF,QAAL,CAAcC,KAAd,CAAH,EAAyB;;YAEpBC,OAAH,EAAY;eACLF,QAAL,CAAcC,KAAd,EAAqBE,MAArB,CAA4B,KAAKH,QAAL,CAAcC,KAAd,EAAqBpJ,OAArB,CAA6BqJ,OAA7B,CAA5B,EAAmE,CAAnE;cACG,KAAKF,QAAL,CAAcC,KAAd,EAAqB/S,MAArB,KAAgC,CAAnC,EAAsC;mBAC7B,KAAK8S,QAAL,CAAcC,KAAd,CAAP;;SAHJ,MAKO;;iBAEE,KAAKD,QAAL,CAAcC,KAAd,CAAP;;;;;;;;;;;;;;;yBAYDA,KA/CP,EA+CclP,IA/Cd,EA+CoB;;UAEb,KAAKiP,QAAL,CAAcC,KAAd,CAAH,EAAyB;aAClBD,QAAL,CAAcC,KAAd,EAAqB5R,OAArB,CAA6B,UAAS6R,OAAT,EAAkB;kBACrCnP,IAAR;SADF;;;;UAMC,KAAKiP,QAAL,CAAc,GAAd,CAAH,EAAuB;aAChBA,QAAL,CAAc,GAAd,EAAmB3R,OAAnB,CAA2B,UAAS+R,WAAT,EAAsB;sBACnCH,KAAZ,EAAmBlP,IAAnB;SADF;;;;;;;;ICrDOsP,SAAb;;;;;;;;;;;qBAWc5U,KAAZ,EAAmBsF,IAAnB,EAAyBwC,cAAzB,EAAyCN,OAAzC,EAAkD+L,iBAAlD,EAAqE;;;SAC9DjG,SAAL,GAAiBvN,gBAAcC,KAAd,CAAjB;SACKsF,IAAL,GAAYA,QAAQ,EAApB;SACKA,IAAL,CAAUkB,MAAV,GAAmB,KAAKlB,IAAL,CAAUkB,MAAV,IAAoB,EAAvC;SACKlB,IAAL,CAAUe,MAAV,GAAmB,KAAKf,IAAL,CAAUe,MAAV,IAAoB,EAAvC;SACKyB,cAAL,GAAsBA,cAAtB;SACKN,OAAL,GAAeA,OAAf;SACK+L,iBAAL,GAAyBA,iBAAzB;SACKzE,YAAL,GAAoB,IAAIwF,YAAJ,EAApB;SACKO,qBAAL,GAA6BrE,YAAY,eAAZ,CAA7B;SACKsE,kBAAL,GAA0BtE,YAAY,0BAAZ,CAA1B;SACKuE,cAAL,GAAsB,SAASA,cAAT,GAAyB;WACxCC,MAAL;KADoB,CAEpBpI,IAFoB,CAEf,IAFe,CAAtB;;QAIG,KAAKU,SAAR,EAAmB;;UAEd,KAAKA,SAAL,CAAe2H,YAAlB,EAAgC;aACzB3H,SAAL,CAAe2H,YAAf,CAA4BC,MAA5B;;;WAGG5H,SAAL,CAAe2H,YAAf,GAA8B,IAA9B;;;;;SAKGE,mBAAL,GAA2BC,WAAW,KAAKC,UAAL,CAAgBzI,IAAhB,CAAqB,IAArB,CAAX,EAAuC,CAAvC,CAA3B;;;;;kCAGY;YACN,IAAIhD,KAAJ,CAAU,yCAAV,CAAN;;;;;;;;;;;;;;;;;;;;2BAiBKtE,IA1DT,EA0DekC,OA1Df,EA0DwB8N,QA1DxB,EA0DkC;UAC3BhQ,IAAH,EAAS;aACFA,IAAL,GAAYA,QAAQ,EAApB;aACKA,IAAL,CAAUkB,MAAV,GAAmB,KAAKlB,IAAL,CAAUkB,MAAV,IAAoB,EAAvC;aACKlB,IAAL,CAAUe,MAAV,GAAmB,KAAKf,IAAL,CAAUe,MAAV,IAAoB,EAAvC;;aAEKyI,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+B;gBACvB,QADuB;gBAEvB,KAAKhL;SAFb;;;UAMCkC,OAAH,EAAY;aACLA,OAAL,GAAe1C,OAAO,EAAP,EAAWwQ,WAAW,KAAK9N,OAAhB,GAA0B,KAAKM,cAA1C,EAA0DN,OAA1D,CAAf;;;;YAIG,CAAC,KAAK2N,mBAAT,EAA8B;eACvB7B,eAAL,CAAqBY,yBAArB;eACKZ,eAAL,GAAuBA,gBAAgB,KAAK9L,OAArB,EAA8B,KAAK+L,iBAAnC,EAAsD,KAAKzE,YAA3D,CAAvB;;;;;UAKD,CAAC,KAAKqG,mBAAT,EAA8B;aACvBI,WAAL,CAAiB,KAAKjC,eAAL,CAAqBe,iBAArB,EAAjB;;;;aAIK,IAAP;;;;;;;;;;;6BAQO;;;UAGJ,CAAC,KAAKc,mBAAT,EAA8B;eACrBK,mBAAP,CAA2B,QAA3B,EAAqC,KAAKT,cAA1C;aACKzB,eAAL,CAAqBY,yBAArB;OAFF,MAGO;eACEuB,YAAP,CAAoB,KAAKN,mBAAzB;;;aAGK,IAAP;;;;;;;;;;;;;uBAUCX,KAnHL,EAmHYC,OAnHZ,EAmHqB;WACZ3F,YAAL,CAAkB4G,eAAlB,CAAkClB,KAAlC,EAAyCC,OAAzC;aACO,IAAP;;;;;;;;;;;;;wBAUED,KA/HN,EA+HaC,OA/Hb,EA+HsB;WACb3F,YAAL,CAAkB6G,kBAAlB,CAAqCnB,KAArC,EAA4CC,OAA5C;aACO,IAAP;;;;iCAGW;;aAEJrE,gBAAP,CAAwB,QAAxB,EAAkC,KAAK2E,cAAvC;;;;WAIKzB,eAAL,GAAuBA,gBAAgB,KAAK9L,OAArB,EAA8B,KAAK+L,iBAAnC,EAAsD,KAAKzE,YAA3D,CAAvB;;WAEKA,YAAL,CAAkB4G,eAAlB,CAAkC,gBAAlC,EAAoD,YAAW;aACxDV,MAAL;OADkD,CAElDpI,IAFkD,CAE7C,IAF6C,CAApD;;;;UAMG,KAAKpF,OAAL,CAAaoO,OAAhB,EAAyB;aAClBpO,OAAL,CAAaoO,OAAb,CAAqBhT,OAArB,CAA6B,UAASiT,MAAT,EAAiB;cACzCA,kBAAkBnU,KAArB,EAA4B;mBACnB,CAAP,EAAU,IAAV,EAAgBmU,OAAO,CAAP,CAAhB;WADF,MAEO;mBACE,IAAP;;SAJyB,CAM3BjJ,IAN2B,CAMtB,IANsB,CAA7B;;;;WAUGkC,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+B;cACvB,SADuB;cAEvB,KAAKhL;OAFb;;;WAMKiQ,WAAL,CAAiB,KAAKjC,eAAL,CAAqBe,iBAArB,EAAjB;;;;WAIKc,mBAAL,GAA2BvU,SAA3B;;;;;;;AC3KJ,kCAAgB,UAAU0N,IAAV,EAAgBjD,IAAhB,EAAsB;MAChC,CAACiD,IAAL,EAAW;UACH,IAAIwH,cAAJ,CAAmB,2DAAnB,CAAN;;;SAGKzK,SAAS,OAAOA,IAAP,KAAgB,QAAhB,IAA4B,OAAOA,IAAP,KAAgB,UAArD,IAAmEA,IAAnE,GAA0EiD,IAAjF;CALF;;ACAA,iBAAgB,UAAUyH,QAAV,EAAoBC,UAApB,EAAgC;MAC1C,OAAOA,UAAP,KAAsB,UAAtB,IAAoCA,eAAe,IAAvD,EAA6D;UACrD,IAAI7L,SAAJ,CAAc,6DAA6D,OAAO6L,UAAlF,CAAN;;;WAGOtP,SAAT,GAAqBjB,OAAOwQ,MAAP,CAAcD,cAAcA,WAAWtP,SAAvC,EAAkD;iBACxD;aACJqP,QADI;kBAEC,KAFD;gBAGD,IAHC;oBAIG;;GALG,CAArB;MAQIC,UAAJ,EAAgBvQ,OAAOyQ,cAAP,GAAwBzQ,OAAOyQ,cAAP,CAAsBH,QAAtB,EAAgCC,UAAhC,CAAxB,GAAsED,SAASI,SAAT,GAAqBH,UAA3F;CAblB;;ACGO,IAAMI,YAAY;KACpB;SACI,GADJ;SAEI,OAFJ;SAGI,YAHJ;eAIU,IAJV;aAKQ,IALR;gBAMW;GAPS;KASpB;SACI,GADJ;SAEI,QAFJ;SAGI,UAHJ;eAIU,IAJV;aAKQ,IALR;gBAMW;;CAfT;;AAmBP,IAAaC,IAAb;;;;;;;+BACa7D,KADb,EACoBR,SADpB,EAC+BsE,KAD/B,EACsC9O,OADtC,EAC+C;WACtCgL,KAAL,GAAaA,KAAb;WACKC,YAAL,GAAoBD,UAAU4D,UAAUnS,CAApB,GAAwBmS,UAAUjP,CAAlC,GAAsCiP,UAAUnS,CAApE;WACKuD,OAAL,GAAeA,OAAf;WACKwK,SAAL,GAAiBA,SAAjB;WACK3O,UAAL,GAAkB2O,UAAU,KAAKQ,KAAL,CAAW+D,OAArB,IAAgCvE,UAAU,KAAKQ,KAAL,CAAWgE,SAArB,CAAlD;WACKC,UAAL,GAAkBzE,UAAU,KAAKQ,KAAL,CAAWkE,UAArB,CAAlB;WACKJ,KAAL,GAAaA,KAAb;;;;iCAGW9V,KAXf,EAWsBqC,KAXtB,EAW6ByC,IAX7B,EAWmC;YACzB,IAAIsE,KAAJ,CAAU,mCAAV,CAAN;;;;wCAGkBgJ,SAftB,EAeiC+D,UAfjC,EAe6C1D,gBAf7C,EAe+D2D,YAf/D,EAe6E9H,YAf7E,EAe2F;UACnF+H,cAAcD,aAAa,SAAS,KAAKpE,KAAL,CAAWnE,GAAX,CAAejG,WAAf,EAAtB,CAAlB;UACI0O,kBAAkB,KAAKR,KAAL,CAAW5T,GAAX,CAAe,KAAKqU,YAAL,CAAkBnK,IAAlB,CAAuB,IAAvB,CAAf,CAAtB;UACIoK,cAAc,KAAKV,KAAL,CAAW5T,GAAX,CAAemU,YAAYI,qBAA3B,CAAlB;;sBAEgBrU,OAAhB,CAAwB,UAASsU,cAAT,EAAyBrU,KAAzB,EAAgC;YAClDmQ,cAAc;aACb,CADa;aAEb;SAFL;;;;YAOImE,WAAJ;YACGL,gBAAgBjU,QAAQ,CAAxB,CAAH,EAA+B;;wBAEfiU,gBAAgBjU,QAAQ,CAAxB,IAA6BqU,cAA3C;SAFF,MAGO;;;;wBAIS1U,KAAKC,GAAL,CAAS,KAAKY,UAAL,GAAkB6T,cAA3B,EAA2C,EAA3C,CAAd;;;;YAICxW,gBAAgBsW,YAAYnU,KAAZ,CAAhB,KAAuCmU,YAAYnU,KAAZ,MAAuB,EAAjE,EAAqE;;;;;;YAMlE,KAAK2P,KAAL,CAAWnE,GAAX,KAAmB,GAAtB,EAA2B;2BACR,KAAK2D,SAAL,CAAe9N,EAAf,GAAoBgT,cAArC;sBACYjT,CAAZ,GAAgB2S,aAAanF,KAAb,CAAmBuB,WAAnB,CAA+B/O,CAA/C;;;;cAIG2S,aAAanF,KAAb,CAAmBU,QAAnB,KAAgC,OAAnC,EAA4C;wBAC9BhL,CAAZ,GAAgB,KAAK6K,SAAL,CAAehB,OAAf,CAAuBE,GAAvB,GAA6B0F,aAAanF,KAAb,CAAmBuB,WAAnB,CAA+B7L,CAA5D,IAAiE8L,mBAAmB,CAAnB,GAAuB,EAAxF,CAAhB;WADF,MAEO;wBACO9L,CAAZ,GAAgB,KAAK6K,SAAL,CAAeC,EAAf,GAAoB2E,aAAanF,KAAb,CAAmBuB,WAAnB,CAA+B7L,CAAnD,IAAwD8L,mBAAmB,CAAnB,GAAuB,EAA/E,CAAhB;;SATJ,MAWO;2BACY,KAAKjB,SAAL,CAAeC,EAAf,GAAoBiF,cAArC;sBACY/P,CAAZ,GAAgByP,aAAalF,KAAb,CAAmBsB,WAAnB,CAA+B7L,CAA/B,IAAoC8L,mBAAmBkE,WAAnB,GAAiC,CAArE,CAAhB;;;;cAIGP,aAAalF,KAAb,CAAmBS,QAAnB,KAAgC,OAAnC,EAA4C;wBAC9BlO,CAAZ,GAAgBgP,mBAAmB,KAAKjB,SAAL,CAAehB,OAAf,CAAuBK,IAAvB,GAA8BuF,aAAalF,KAAb,CAAmBsB,WAAnB,CAA+B/O,CAAhF,GAAoF,KAAK+N,SAAL,CAAe9N,EAAf,GAAoB,EAAxH;WADF,MAEO;wBACOD,CAAZ,GAAgB,KAAK+N,SAAL,CAAe7N,EAAf,GAAoByS,aAAalF,KAAb,CAAmBsB,WAAnB,CAA+B/O,CAAnD,GAAuD,EAAvE;;;;YAID4S,YAAYO,QAAf,EAAyB;qBACZF,cAAX,EAA2BrU,KAA3B,EAAkC,IAAlC,EAAwC,KAAK4T,UAA7C,EAAyD,KAAKzE,SAAL,CAAe,KAAKS,YAAL,CAAkBU,GAAjC,GAAzD,EAAkGP,SAAlG,EAA6G,CAC3GgE,aAAaS,UAAb,CAAwBC,IADmF,EAE3GV,aAAaS,UAAb,CAAwB,KAAK7E,KAAL,CAAW+E,GAAnC,CAF2G,CAA7G,EAGGzI,YAHH;;;YAMC+H,YAAYW,SAAf,EAA0B;sBACZN,cAAZ,EAA4BC,WAA5B,EAAyCtU,KAAzC,EAAgDmU,WAAhD,EAA6D,IAA7D,EAAmEH,YAAYjF,MAA/E,EAAuFoB,WAAvF,EAAoG2D,UAApG,EAAgH,CAC9GC,aAAaS,UAAb,CAAwBI,KADsF,EAE9Gb,aAAaS,UAAb,CAAwB,KAAK7E,KAAL,CAAW+E,GAAnC,CAF8G,EAG7GV,YAAY1E,QAAZ,KAAyB,OAAzB,GAAmCyE,aAAaS,UAAb,CAAwBR,YAAY1E,QAApC,CAAnC,GAAmFyE,aAAaS,UAAb,CAAwB,KAAxB,CAH0B,CAAhH,EAIGpE,gBAJH,EAIqBnE,YAJrB;;OA1DoB,CAgEtBlC,IAhEsB,CAgEjB,IAhEiB,CAAxB;;;;;;;AC1CJ,YAAgB,SAAS8K,GAAT,CAAatX,MAAb,EAAqBC,QAArB,EAA+BsX,QAA/B,EAAyC;MACnDvX,WAAW,IAAf,EAAqBA,SAASwX,SAASlR,SAAlB;MACjBmR,OAAOpS,OAAOqS,wBAAP,CAAgC1X,MAAhC,EAAwCC,QAAxC,CAAX;;MAEIwX,SAASjX,SAAb,EAAwB;QAClB6K,SAAShG,OAAOsS,cAAP,CAAsB3X,MAAtB,CAAb;;QAEIqL,WAAW,IAAf,EAAqB;aACZ7K,SAAP;KADF,MAEO;aACE8W,IAAIjM,MAAJ,EAAYpL,QAAZ,EAAsBsX,QAAtB,CAAP;;GANJ,MAQO,IAAI,WAAWE,IAAf,EAAqB;WACnBA,KAAKrX,KAAZ;GADK,MAEA;QACDwX,SAASH,KAAKH,GAAlB;;QAEIM,WAAWpX,SAAf,EAA0B;aACjBA,SAAP;;;WAGKoX,OAAO3M,IAAP,CAAYsM,QAAZ,CAAP;;CArBJ;;ICGaM,aAAb;;;yBACcC,QAAZ,EAAsB5S,IAAtB,EAA4B0M,SAA5B,EAAuCxK,OAAvC,EAAgD;;;;;;QAG1Ca,UAAUb,QAAQa,OAAR,IAAmBF,WAAW7C,IAAX,EAAiBkC,OAAjB,EAA0B0Q,SAAS7J,GAAnC,CAAjC;UACK/K,MAAL,GAAcyF,UAAUiJ,UAAUkG,SAAS3B,OAAnB,IAA8BvE,UAAUkG,SAAS1B,SAAnB,CAAxC,EAAuEnO,OAAvE,EAAgFb,QAAQwB,aAAR,IAAyB,EAAzG,EAA6GxB,QAAQyB,WAArH,CAAd;UACK1F,KAAL,GAAa;WACN,MAAKD,MAAL,CAAYwF,GADN;WAEN,MAAKxF,MAAL,CAAYb;KAFnB;;+HAKiByV,QAAjB,EAA2BlG,SAA3B,EAAsC,MAAK1O,MAAL,CAAY0G,MAAlD,EAA0DxC,OAA1D;;;;;;iCAGWhH,KAdf,EAcsB;aACX,KAAK6C,UAAL,IAAmB,CAACgE,cAAc7G,KAAd,EAAqB,KAAKgS,KAAL,CAAWnE,GAAhC,CAAD,GAAwC,KAAK/K,MAAL,CAAYwF,GAAvE,IAA8E,KAAKxF,MAAL,CAAYC,KAAjG;;;;;EAf+B8S,IAAnC;;ICCa8B,cAAb;;;0BACcD,QAAZ,EAAsB5S,IAAtB,EAA4B0M,SAA5B,EAAuCxK,OAAvC,EAAgD;;;;;QAG1Ca,UAAUb,QAAQa,OAAR,IAAmBF,WAAW7C,IAAX,EAAiBkC,OAAjB,EAA0B0Q,SAAS7J,GAAnC,CAAjC;UACKjK,OAAL,GAAeoD,QAAQpD,OAAR,IAAmB,CAAlC;UACKkS,KAAL,GAAa9O,QAAQ8O,KAAR,IAAiB9U,MAAM,MAAK4C,OAAX,EAAoB1B,GAApB,CAAwB,UAASlC,KAAT,EAAgBqC,KAAhB,EAAuB;aAClEwF,QAAQI,GAAR,GAAc,CAACJ,QAAQC,IAAR,GAAeD,QAAQI,GAAxB,IAA+B,KAAKrE,OAApC,GAA8CvB,KAAnE;KADkD,CAElD+J,IAFkD,OAAxB,CAA9B;UAGK0J,KAAL,CAAW8B,IAAX,CAAgB,UAASC,CAAT,EAAYC,CAAZ,EAAe;aACtBD,IAAIC,CAAX;KADF;UAGK/U,KAAL,GAAa;WACN8E,QAAQI,GADF;WAENJ,QAAQC;KAFf;;iIAKiB4P,QAAjB,EAA2BlG,SAA3B,EAAsC,MAAKsE,KAA3C,EAAkD9O,OAAlD;;UAEK+Q,UAAL,GAAkB,MAAKlV,UAAL,GAAkB,MAAKe,OAAzC;;;;;;iCAGW5D,KAtBf,EAsBsB;aACX,KAAK6C,UAAL,IAAmB,CAACgE,cAAc7G,KAAd,EAAqB,KAAKgS,KAAL,CAAWnE,GAAhC,CAAD,GAAwC,KAAK9K,KAAL,CAAWuF,GAAtE,KAA8E,KAAKvF,KAAL,CAAWd,GAAX,GAAiB,KAAKc,KAAL,CAAWuF,GAA1G,CAAP;;;;;EAvBgCuN,IAApC;;ICFamC,QAAb;;;oBACcN,QAAZ,EAAsB5S,IAAtB,EAA4B0M,SAA5B,EAAuCxK,OAAvC,EAAgD;;;;;qHAE7B0Q,QAAjB,EAA2BlG,SAA3B,EAAsCxK,QAAQ8O,KAA9C,EAAqD9O,OAArD;;QAEIiR,OAAOjW,KAAKC,GAAL,CAAS,CAAT,EAAY+E,QAAQ8O,KAAR,CAAc7U,MAAd,IAAwB+F,QAAQkR,OAAR,GAAkB,CAAlB,GAAsB,CAA9C,CAAZ,CAAX;UACKH,UAAL,GAAkB,MAAKlV,UAAL,GAAkBoV,IAApC;;;;;;iCAGWjY,KATf,EASsBqC,KATtB,EAS6B;aAClB,KAAK0V,UAAL,GAAkB1V,KAAzB;;;;;EAV0BwT,IAA9B;;ACAA;;;;;;AAMA,IAAMsC,sBAAsB;KACvB,CAAC,GAAD,EAAM,GAAN,CADuB;KAEvB,CAAC,GAAD,EAAM,GAAN,CAFuB;KAGvB,CAAC,IAAD,EAAO,IAAP,EAAa,IAAb,EAAmB,IAAnB,EAAyB,GAAzB,EAA8B,GAA9B,CAHuB;KAIvB,CAAC,IAAD,EAAO,IAAP,EAAa,KAAb,EAAoB,KAApB,EAA2B,IAA3B,EAAiC,GAAjC,EAAsC,GAAtC;CAJL;;;;;;;;AAaA,IAAM7Q,mBAAiB;;YAEX;CAFZ;;AAKA,SAASwD,OAAT,CAAiBsN,OAAjB,EAA0BC,MAA1B,EAAkCC,YAAlC,EAAgDzK,GAAhD,EAAqD0K,QAArD,EAA+DzT,IAA/D,EAAqE;MAC/D0T,cAAclU,OAAO;aACdiU,WAAWH,QAAQK,WAAR,EAAX,GAAmCL,QAAQxQ,WAAR;GAD5B,EAEfyQ,MAFe,EAEPvT,OAAO,EAAEA,MAAMA,IAAR,EAAP,GAAwB,EAFjB,CAAlB;;eAIaoP,MAAb,CAAoBrG,GAApB,EAAyB,CAAzB,EAA4B2K,WAA5B;;;AAGF,SAASE,YAAT,CAAsBJ,YAAtB,EAAoCxW,EAApC,EAAwC;eACzBM,OAAb,CAAqB,UAASoW,WAAT,EAAsBG,gBAAtB,EAAwC;wBACvCH,YAAYJ,OAAZ,CAAoBK,WAApB,EAApB,EAAuDrW,OAAvD,CAA+D,UAASwW,SAAT,EAAoBC,UAApB,EAAgC;SAC1FL,WAAH,EAAgBI,SAAhB,EAA2BD,gBAA3B,EAA6CE,UAA7C,EAAyDP,YAAzD;KADF;GADF;;;;;;;;;;;AAeF,IAAaQ,OAAb;;;;;;;;;;;;;yBAUcC,KAVd,EAUqBC,KAVrB,EAU4BhS,OAV5B,EAUqC;UAC7BiS,aAAa,IAAIH,OAAJ,CAAYE,KAAZ,EAAmBhS,OAAnB,CAAjB;WACI,IAAIxC,IAAI,CAAZ,EAAeA,IAAIuU,MAAM9X,MAAzB,EAAiCuD,GAAjC,EAAsC;YAChC0U,OAAOH,MAAMvU,CAAN,CAAX;aACI,IAAI2U,IAAI,CAAZ,EAAeA,IAAID,KAAKZ,YAAL,CAAkBrX,MAArC,EAA6CkY,GAA7C,EAAkD;qBACrCb,YAAX,CAAwBnS,IAAxB,CAA6B+S,KAAKZ,YAAL,CAAkBa,CAAlB,CAA7B;;;aAGGF,UAAP;;;;mBAGUD,KAAZ,EAAmBhS,OAAnB,EAA4B;;;SACrBsR,YAAL,GAAoB,EAApB;SACKzK,GAAL,GAAW,CAAX;SACKmL,KAAL,GAAaA,KAAb;SACKhS,OAAL,GAAe1C,OAAO,EAAP,EAAWgD,gBAAX,EAA2BN,OAA3B,CAAf;;;;;;;;;;;;;;6BAUO6G,GAnCX,EAmCgB;UACTA,QAAQzN,SAAX,EAAsB;aACfyN,GAAL,GAAW7L,KAAKC,GAAL,CAAS,CAAT,EAAYD,KAAKsG,GAAL,CAAS,KAAKgQ,YAAL,CAAkBrX,MAA3B,EAAmC4M,GAAnC,CAAZ,CAAX;eACO,IAAP;OAFF,MAGO;eACE,KAAKA,GAAZ;;;;;;;;;;;;;;2BAWGuL,KAnDT,EAmDgB;WACPd,YAAL,CAAkBpE,MAAlB,CAAyB,KAAKrG,GAA9B,EAAmCuL,KAAnC;aACO,IAAP;;;;;;;;;;;;;;;;yBAaG3V,CAlEP,EAkEUkD,CAlEV,EAkEa4R,QAlEb,EAkEuBzT,IAlEvB,EAkE6B;cACjB,GAAR,EAAa;WACR,CAACrB,CADO;WAER,CAACkD;OAFN,EAGG,KAAK2R,YAHR,EAGsB,KAAKzK,GAAL,EAHtB,EAGkC0K,QAHlC,EAG4CzT,IAH5C;aAIO,IAAP;;;;;;;;;;;;;;;;yBAaGrB,CApFP,EAoFUkD,CApFV,EAoFa4R,QApFb,EAoFuBzT,IApFvB,EAoF6B;cACjB,GAAR,EAAa;WACR,CAACrB,CADO;WAER,CAACkD;OAFN,EAGG,KAAK2R,YAHR,EAGsB,KAAKzK,GAAL,EAHtB,EAGkC0K,QAHlC,EAG4CzT,IAH5C;aAIO,IAAP;;;;;;;;;;;;;;;;;;;;0BAiBIpB,EA1GR,EA0GY+N,EA1GZ,EA0GgB9N,EA1GhB,EA0GoB+N,EA1GpB,EA0GwBjO,CA1GxB,EA0G2BkD,CA1G3B,EA0G8B4R,QA1G9B,EA0GwCzT,IA1GxC,EA0G8C;cAClC,GAAR,EAAa;YACP,CAACpB,EADM;YAEP,CAAC+N,EAFM;YAGP,CAAC9N,EAHM;YAIP,CAAC+N,EAJM;WAKR,CAACjO,CALO;WAMR,CAACkD;OANN,EAOG,KAAK2R,YAPR,EAOsB,KAAKzK,GAAL,EAPtB,EAOkC0K,QAPlC,EAO4CzT,IAP5C;aAQO,IAAP;;;;;;;;;;;;;;;;;;;;;wBAkBEuU,EArIN,EAqIUC,EArIV,EAqIcC,GArId,EAqImBC,GArInB,EAqIwBC,EArIxB,EAqI4BhW,CArI5B,EAqI+BkD,CArI/B,EAqIkC4R,QArIlC,EAqI4CzT,IArI5C,EAqIkD;cACtC,GAAR,EAAa;YACP,CAACuU,EADM;YAEP,CAACC,EAFM;aAGN,CAACC,GAHK;aAIN,CAACC,GAJK;YAKP,CAACC,EALM;WAMR,CAAChW,CANO;WAOR,CAACkD;OAPN,EAQG,KAAK2R,YARR,EAQsB,KAAKzK,GAAL,EARtB,EAQkC0K,QARlC,EAQ4CzT,IAR5C;aASO,IAAP;;;;;;;;;;;;;0BAUIoU,IAzJR,EAyJc;;UAENQ,SAASR,KAAK7Z,OAAL,CAAa,oBAAb,EAAmC,OAAnC,EACVA,OADU,CACF,oBADE,EACoB,OADpB,EAEV4M,KAFU,CAEJ,QAFI,EAGV9G,MAHU,CAGH,UAASpD,MAAT,EAAiB+I,OAAjB,EAA0B;YAC7BA,QAAQrK,KAAR,CAAc,UAAd,CAAH,EAA8B;iBACrB0F,IAAP,CAAY,EAAZ;;;eAGKpE,OAAOd,MAAP,GAAgB,CAAvB,EAA0BkF,IAA1B,CAA+B2E,OAA/B;eACO/I,MAAP;OATS,EAUR,EAVQ,CAAb;;;UAaG2X,OAAOA,OAAOzY,MAAP,GAAgB,CAAvB,EAA0B,CAA1B,EAA6B2G,WAA7B,OAA+C,GAAlD,EAAuD;eAC9C+R,GAAP;;;;;UAKEC,WAAWF,OAAOxX,GAAP,CAAW,UAAS2X,KAAT,EAAgB;YACpCzB,UAAUyB,MAAMC,KAAN,EAAd;YACEC,cAAc5B,oBAAoBC,QAAQK,WAAR,EAApB,CADhB;;eAGOnU,OAAO;mBACH8T;SADJ,EAEJ2B,YAAY5U,MAAZ,CAAmB,UAASpD,MAAT,EAAiB6W,SAAjB,EAA4BvW,KAA5B,EAAmC;iBAChDuW,SAAP,IAAoB,CAACiB,MAAMxX,KAAN,CAArB;iBACON,MAAP;SAFC,EAGA,EAHA,CAFI,CAAP;OAJa,CAAf;;;UAaIiY,aAAa,CAAC,KAAKnM,GAAN,EAAW,CAAX,CAAjB;YACM3H,SAAN,CAAgBC,IAAhB,CAAqBhF,KAArB,CAA2B6Y,UAA3B,EAAuCJ,QAAvC;YACM1T,SAAN,CAAgBgO,MAAhB,CAAuB/S,KAAvB,CAA6B,KAAKmX,YAAlC,EAAgD0B,UAAhD;;WAEKnM,GAAL,IAAY+L,SAAS3Y,MAArB;;aAEO,IAAP;;;;;;;;;;;;gCASU;UACNgZ,qBAAqBjY,KAAKkB,GAAL,CAAS,EAAT,EAAa,KAAK8D,OAAL,CAAakT,QAA1B,CAAzB;;aAEO,KAAK5B,YAAL,CAAkBnT,MAAlB,CAAyB,UAAS+T,IAAT,EAAeV,WAAf,EAA4B;YACpDH,SAASF,oBAAoBK,YAAYJ,OAAZ,CAAoBK,WAApB,EAApB,EAAuDvW,GAAvD,CAA2D,UAAS0W,SAAT,EAAoB;iBACnF,KAAK5R,OAAL,CAAakT,QAAb,GACJlY,KAAKmB,KAAL,CAAWqV,YAAYI,SAAZ,IAAyBqB,kBAApC,IAA0DA,kBADtD,GAELzB,YAAYI,SAAZ,CAFF;SADsE,CAItExM,IAJsE,CAIjE,IAJiE,CAA3D,CAAb;;eAMO8M,OAAOV,YAAYJ,OAAnB,GAA6BC,OAAOtK,IAAP,CAAY,GAAZ,CAApC;OAP4B,CAQ5B3B,IAR4B,CAQvB,IARuB,CAAzB,EAQS,EART,KAQgB,KAAK4M,KAAL,GAAa,GAAb,GAAmB,EARnC,CAAP;;;;;;;;;;;;;;0BAmBIvV,CAhOR,EAgOWkD,CAhOX,EAgOc;mBACG,KAAK2R,YAAlB,EAAgC,UAASE,WAAT,EAAsBI,SAAtB,EAAiC;oBACnDA,SAAZ,KAA0BA,UAAU,CAAV,MAAiB,GAAjB,GAAuBnV,CAAvB,GAA2BkD,CAArD;OADF;aAGO,IAAP;;;;;;;;;;;;;;8BAWQlD,CA/OZ,EA+OekD,CA/Of,EA+OkB;mBACD,KAAK2R,YAAlB,EAAgC,UAASE,WAAT,EAAsBI,SAAtB,EAAiC;oBACnDA,SAAZ,KAA0BA,UAAU,CAAV,MAAiB,GAAjB,GAAuBnV,CAAvB,GAA2BkD,CAArD;OADF;aAGO,IAAP;;;;;;;;;;;;;;;;;;8BAeQwT,YAlQZ,EAkQ0B;mBACT,KAAK7B,YAAlB,EAAgC,UAASE,WAAT,EAAsBI,SAAtB,EAAiCD,gBAAjC,EAAmDE,UAAnD,EAA+DP,YAA/D,EAA6E;YACvG8B,cAAcD,aAAa3B,WAAb,EAA0BI,SAA1B,EAAqCD,gBAArC,EAAuDE,UAAvD,EAAmEP,YAAnE,CAAlB;YACG8B,eAAeA,gBAAgB,CAAlC,EAAqC;sBACvBxB,SAAZ,IAAyBwB,WAAzB;;OAHJ;aAMO,IAAP;;;;;;;;;;;;;0BAUIpB,KAnRR,EAmRe;UACPqB,IAAI,IAAIvB,OAAJ,CAAYE,SAAS,KAAKA,KAA1B,CAAR;QACEnL,GAAF,GAAQ,KAAKA,GAAb;QACEyK,YAAF,GAAiB,KAAKA,YAAL,CAAkBrS,KAAlB,GAA0B/D,GAA1B,CAA8B,SAASoY,aAAT,CAAuB9B,WAAvB,EAAoC;eAC1ElU,OAAO,EAAP,EAAWkU,WAAX,CAAP;OADe,CAAjB;QAGExR,OAAF,GAAY1C,OAAO,EAAP,EAAW,KAAK0C,OAAhB,CAAZ;aACOqT,CAAP;;;;;;;;;;;;;mCAUajC,OApSjB,EAoS0B;UAClBnM,QAAQ,CACV,IAAI6M,OAAJ,EADU,CAAZ;;WAIKR,YAAL,CAAkBlW,OAAlB,CAA0B,UAASoW,WAAT,EAAsB;YAC3CA,YAAYJ,OAAZ,KAAwBA,QAAQxQ,WAAR,EAAxB,IAAiDqE,MAAMA,MAAMhL,MAAN,GAAe,CAArB,EAAwBqX,YAAxB,CAAqCrX,MAArC,KAAgD,CAApG,EAAuG;gBAC/FkF,IAAN,CAAW,IAAI2S,OAAJ,EAAX;;;cAGI7M,MAAMhL,MAAN,GAAe,CAArB,EAAwBqX,YAAxB,CAAqCnS,IAArC,CAA0CqS,WAA1C;OALF;;aAQOvM,KAAP;;;;;;;AChWJ;;;;;;;;;;;;;;;;;AAiBA,AAAO,SAASsO,IAAT,CAAcvT,OAAd,EAAuB;MACxBM,iBAAiB;eACR;GADb;YAGUhD,OAAO,EAAP,EAAWgD,cAAX,EAA2BN,OAA3B,CAAV;SACO,SAASuT,IAAT,CAAcnT,eAAd,EAA+BC,SAA/B,EAA0C;QAC3C6R,OAAO,IAAIJ,OAAJ,EAAX;QACItR,OAAO,IAAX;;SAEI,IAAIhD,IAAI,CAAZ,EAAeA,IAAI4C,gBAAgBnG,MAAnC,EAA2CuD,KAAK,CAAhD,EAAmD;UAC7CgW,QAAQpT,gBAAgB5C,CAAhB,CAAZ;UACIiW,QAAQrT,gBAAgB5C,IAAI,CAApB,CAAZ;UACIkW,WAAWrT,UAAU7C,IAAI,CAAd,CAAf;;UAEGqC,cAAc6T,SAAS1a,KAAvB,MAAkCI,SAArC,EAAgD;;YAE3CoH,IAAH,EAAS;eACFmT,IAAL,CAAUH,KAAV,EAAiBC,KAAjB,EAAwB,KAAxB,EAA+BC,QAA/B;SADF,MAEO;eACAE,IAAL,CAAUJ,KAAV,EAAiBC,KAAjB,EAAwB,KAAxB,EAA+BC,QAA/B;;;eAGK,KAAP;OARF,MASO,IAAG,CAAC1T,QAAQS,SAAZ,EAAuB;eACrB,IAAP;;;;WAIGyR,IAAP;GAvBF;;;ACtBF;;;;;;;;;;;;;;;;;;;;;;;AAuBA,AAAO,SAAS2B,MAAT,CAAgB7T,OAAhB,EAAyB;MAC1BM,iBAAiB;aACV,CADU;eAER;GAFb;YAIUhD,OAAO,EAAP,EAAWgD,cAAX,EAA2BN,OAA3B,CAAV;;MAEI8T,IAAI,IAAI9Y,KAAKC,GAAL,CAAS,CAAT,EAAY+E,QAAQpD,OAApB,CAAZ;;SAEO,SAASiX,MAAT,CAAgBzT,eAAhB,EAAiCC,SAAjC,EAA4C;QAC7C6R,OAAO,IAAIJ,OAAJ,EAAX;QACIiC,KAAJ,EAAWC,KAAX,EAAkBC,QAAlB;;SAEI,IAAIzW,IAAI,CAAZ,EAAeA,IAAI4C,gBAAgBnG,MAAnC,EAA2CuD,KAAK,CAAhD,EAAmD;UAC7CgW,QAAQpT,gBAAgB5C,CAAhB,CAAZ;UACIiW,QAAQrT,gBAAgB5C,IAAI,CAApB,CAAZ;UACIvD,SAAS,CAACuZ,QAAQO,KAAT,IAAkBD,CAA/B;UACIJ,WAAWrT,UAAU7C,IAAI,CAAd,CAAf;;UAEGkW,SAAS1a,KAAT,KAAmBI,SAAtB,EAAiC;;YAE5B6a,aAAa7a,SAAhB,EAA2B;eACpBua,IAAL,CAAUH,KAAV,EAAiBC,KAAjB,EAAwB,KAAxB,EAA+BC,QAA/B;SADF,MAEO;eACAQ,KAAL,CACEH,QAAQ9Z,MADV,EAEE+Z,KAFF,EAGER,QAAQvZ,MAHV,EAIEwZ,KAJF,EAKED,KALF,EAMEC,KANF,EAOE,KAPF,EAQEC,QARF;;;gBAYMF,KAAR;gBACQC,KAAR;mBACWC,QAAX;OAnBF,MAoBO,IAAG,CAAC1T,QAAQS,SAAZ,EAAuB;gBACpB+S,QAAQS,WAAW7a,SAA3B;;;;WAIG8Y,IAAP;GAnCF;;;AChCF;;;;;;;;;;;;;;;;;;;;AAoBA,AAAO,SAASnQ,IAAT,CAAc/B,OAAd,EAAuB;MACxBM,iBAAiB;cACT,IADS;eAER;GAFb;;YAKUhD,OAAO,EAAP,EAAWgD,cAAX,EAA2BN,OAA3B,CAAV;;SAEO,SAAS+B,IAAT,CAAc3B,eAAd,EAA+BC,SAA/B,EAA0C;QAC3C6R,OAAO,IAAIJ,OAAJ,EAAX;;QAEIiC,KAAJ,EAAWC,KAAX,EAAkBC,QAAlB;;SAEK,IAAIzW,IAAI,CAAb,EAAgBA,IAAI4C,gBAAgBnG,MAApC,EAA4CuD,KAAK,CAAjD,EAAoD;UAC9CgW,QAAQpT,gBAAgB5C,CAAhB,CAAZ;UACIiW,QAAQrT,gBAAgB5C,IAAI,CAApB,CAAZ;UACIkW,WAAWrT,UAAU7C,IAAI,CAAd,CAAf;;;UAGGkW,SAAS1a,KAAT,KAAmBI,SAAtB,EAAiC;YAC5B6a,aAAa7a,SAAhB,EAA2B;eACpBua,IAAL,CAAUH,KAAV,EAAiBC,KAAjB,EAAwB,KAAxB,EAA+BC,QAA/B;SADF,MAEO;cACF1T,QAAQmU,QAAX,EAAqB;;iBAEdP,IAAL,CAAUJ,KAAV,EAAiBQ,KAAjB,EAAwB,KAAxB,EAA+BC,QAA/B;WAFF,MAGO;;iBAEAL,IAAL,CAAUG,KAAV,EAAiBN,KAAjB,EAAwB,KAAxB,EAA+BC,QAA/B;;;eAGGE,IAAL,CAAUJ,KAAV,EAAiBC,KAAjB,EAAwB,KAAxB,EAA+BC,QAA/B;;;gBAGMF,KAAR;gBACQC,KAAR;mBACWC,QAAX;OAjBF,MAkBO,IAAG,CAAC1T,QAAQS,SAAZ,EAAuB;gBACpBuT,QAAQC,WAAW7a,SAA3B;;;;WAIG8Y,IAAP;GAlCF;;;AC3BF;;;;;;;;;;;;;;;;;;;;;;AAsBA,AAAO,SAASkC,QAAT,CAAkBpU,OAAlB,EAA2B;MAC5BM,iBAAiB;aACV,CADU;eAER;GAFb;;YAKUhD,OAAO,EAAP,EAAWgD,cAAX,EAA2BN,OAA3B,CAAV;;MAEIoG,IAAIpL,KAAKsG,GAAL,CAAS,CAAT,EAAYtG,KAAKC,GAAL,CAAS,CAAT,EAAY+E,QAAQqU,OAApB,CAAZ,CAAR;MACEhB,IAAI,IAAIjN,CADV;;SAGO,SAASgO,QAAT,CAAkBhU,eAAlB,EAAmCC,SAAnC,EAA8C;;;QAG/CE,WAAWJ,kBAAkBC,eAAlB,EAAmCC,SAAnC,EAA8C;iBAChDL,QAAQS;KADN,CAAf;;QAIG,CAACF,SAAStG,MAAb,EAAqB;;aAEZsZ,OAAO,EAAP,CAAP;KAFF,MAGO,IAAGhT,SAAStG,MAAT,GAAkB,CAArB,EAAwB;;;UAGzB8X,QAAQ,EAAZ;;eAES3W,OAAT,CAAiB,UAASkZ,OAAT,EAAkB;cAC3BnV,IAAN,CAAWiV,SAASE,QAAQlU,eAAjB,EAAkCkU,QAAQjU,SAA1C,CAAX;OADF;;aAIOyR,QAAQ/K,IAAR,CAAagL,KAAb,CAAP;KATK,MAUA;;;wBAGaxR,SAAS,CAAT,EAAYH,eAA9B;kBACYG,SAAS,CAAT,EAAYF,SAAxB;;;UAGGD,gBAAgBnG,MAAhB,IAA0B,CAA7B,EAAgC;eACvBsZ,OAAOnT,eAAP,EAAwBC,SAAxB,CAAP;;;UAGE6R,OAAO,IAAIJ,OAAJ,GAAc6B,IAAd,CAAmBvT,gBAAgB,CAAhB,CAAnB,EAAuCA,gBAAgB,CAAhB,CAAvC,EAA2D,KAA3D,EAAkEC,UAAU,CAAV,CAAlE,CAAX;UACEkU,CADF;;WAGK,IAAI/W,IAAI,CAAR,EAAWgX,OAAOpU,gBAAgBnG,MAAvC,EAA+Cua,OAAO,IAAI,CAACD,CAAZ,GAAgB/W,CAA/D,EAAkEA,KAAK,CAAvE,EAA0E;YACpElB,IAAI,CACN,EAACG,GAAG,CAAC2D,gBAAgB5C,IAAI,CAApB,CAAL,EAA6BmC,GAAG,CAACS,gBAAgB5C,IAAI,CAApB,CAAjC,EADM,EAEN,EAACf,GAAG,CAAC2D,gBAAgB5C,CAAhB,CAAL,EAAyBmC,GAAG,CAACS,gBAAgB5C,IAAI,CAApB,CAA7B,EAFM,EAGN,EAACf,GAAG,CAAC2D,gBAAgB5C,IAAI,CAApB,CAAL,EAA6BmC,GAAG,CAACS,gBAAgB5C,IAAI,CAApB,CAAjC,EAHM,EAIN,EAACf,GAAG,CAAC2D,gBAAgB5C,IAAI,CAApB,CAAL,EAA6BmC,GAAG,CAACS,gBAAgB5C,IAAI,CAApB,CAAjC,EAJM,CAAR;YAMI+W,CAAJ,EAAO;cACD,CAAC/W,CAAL,EAAQ;cACJ,CAAF,IAAO,EAACf,GAAG,CAAC2D,gBAAgBoU,OAAO,CAAvB,CAAL,EAAgC7U,GAAG,CAACS,gBAAgBoU,OAAO,CAAvB,CAApC,EAAP;WADF,MAEO,IAAIA,OAAO,CAAP,KAAahX,CAAjB,EAAoB;cACvB,CAAF,IAAO,EAACf,GAAG,CAAC2D,gBAAgB,CAAhB,CAAL,EAAyBT,GAAG,CAACS,gBAAgB,CAAhB,CAA7B,EAAP;WADK,MAEA,IAAIoU,OAAO,CAAP,KAAahX,CAAjB,EAAoB;cACvB,CAAF,IAAO,EAACf,GAAG,CAAC2D,gBAAgB,CAAhB,CAAL,EAAyBT,GAAG,CAACS,gBAAgB,CAAhB,CAA7B,EAAP;cACE,CAAF,IAAO,EAAC3D,GAAG,CAAC2D,gBAAgB,CAAhB,CAAL,EAAyBT,GAAG,CAACS,gBAAgB,CAAhB,CAA7B,EAAP;;SAPJ,MASO;cACDoU,OAAO,CAAP,KAAahX,CAAjB,EAAoB;cAChB,CAAF,IAAOlB,EAAE,CAAF,CAAP;WADF,MAEO,IAAI,CAACkB,CAAL,EAAQ;cACX,CAAF,IAAO,EAACf,GAAG,CAAC2D,gBAAgB5C,CAAhB,CAAL,EAAyBmC,GAAG,CAACS,gBAAgB5C,IAAI,CAApB,CAA7B,EAAP;;;;aAIC0W,KAAL,CACG9N,KAAK,CAAC9J,EAAE,CAAF,EAAKG,CAAN,GAAU,IAAIH,EAAE,CAAF,EAAKG,CAAnB,GAAuBH,EAAE,CAAF,EAAKG,CAAjC,IAAsC,CAAvC,GAA6C4W,IAAI/W,EAAE,CAAF,EAAKG,CADxD,EAEG2J,KAAK,CAAC9J,EAAE,CAAF,EAAKqD,CAAN,GAAU,IAAIrD,EAAE,CAAF,EAAKqD,CAAnB,GAAuBrD,EAAE,CAAF,EAAKqD,CAAjC,IAAsC,CAAvC,GAA6C0T,IAAI/W,EAAE,CAAF,EAAKqD,CAFxD,EAGGyG,KAAK9J,EAAE,CAAF,EAAKG,CAAL,GAAS,IAAIH,EAAE,CAAF,EAAKG,CAAlB,GAAsBH,EAAE,CAAF,EAAKG,CAAhC,IAAqC,CAAtC,GAA4C4W,IAAI/W,EAAE,CAAF,EAAKG,CAHvD,EAIG2J,KAAK9J,EAAE,CAAF,EAAKqD,CAAL,GAAS,IAAIrD,EAAE,CAAF,EAAKqD,CAAlB,GAAsBrD,EAAE,CAAF,EAAKqD,CAAhC,IAAqC,CAAtC,GAA4C0T,IAAI/W,EAAE,CAAF,EAAKqD,CAJvD,EAKErD,EAAE,CAAF,EAAKG,CALP,EAMEH,EAAE,CAAF,EAAKqD,CANP,EAOE,KAPF,EAQEU,UAAU,CAAC7C,IAAI,CAAL,IAAU,CAApB,CARF;;;aAYK0U,IAAP;;GAtEJ;;;ACjCF;;;;;;;;;;;;;;;;;;;;;;;AAuBA,AAAO,SAASuC,aAAT,CAAuBzU,OAAvB,EAAgC;MACjCM,iBAAiB;eACR;GADb;;YAIUhD,OAAO,EAAP,EAAWgD,cAAX,EAA2BN,OAA3B,CAAV;;SAEO,SAASyU,aAAT,CAAuBrU,eAAvB,EAAwCC,SAAxC,EAAmD;;;QAGpDE,WAAWJ,kBAAkBC,eAAlB,EAAmCC,SAAnC,EAA8C;iBAChDL,QAAQS,SADwC;mBAE9C;KAFA,CAAf;;QAKG,CAACF,SAAStG,MAAb,EAAqB;;aAEZsZ,OAAO,EAAP,CAAP;KAFF,MAGO,IAAGhT,SAAStG,MAAT,GAAkB,CAArB,EAAwB;;;UAGzB8X,QAAQ,EAAZ;;eAES3W,OAAT,CAAiB,UAASkZ,OAAT,EAAkB;cAC3BnV,IAAN,CAAWsV,cAAcH,QAAQlU,eAAtB,EAAuCkU,QAAQjU,SAA/C,CAAX;OADF;;aAIOyR,QAAQ/K,IAAR,CAAagL,KAAb,CAAP;KATK,MAUA;;;wBAGaxR,SAAS,CAAT,EAAYH,eAA9B;kBACYG,SAAS,CAAT,EAAYF,SAAxB;;;UAGGD,gBAAgBnG,MAAhB,IAA0B,CAA7B,EAAgC;eACvBsZ,OAAOnT,eAAP,EAAwBC,SAAxB,CAAP;;;UAGEqU,KAAK,EAAT;UACEC,KAAK,EADP;UAEEnX,CAFF;UAGE5D,IAAIwG,gBAAgBnG,MAAhB,GAAyB,CAH/B;UAIE2a,KAAK,EAJP;UAKEC,KAAK,EALP;UAKWC,MAAM,EALjB;UAKqBC,MAAM,EAL3B;UAME7C,IANF;;;;WAUI1U,IAAI,CAAR,EAAWA,IAAI5D,CAAf,EAAkB4D,GAAlB,EAAuB;WAClBA,CAAH,IAAQ4C,gBAAgB5C,IAAI,CAApB,CAAR;WACGA,CAAH,IAAQ4C,gBAAgB5C,IAAI,CAAJ,GAAQ,CAAxB,CAAR;;;;;WAKEA,IAAI,CAAR,EAAWA,IAAI5D,IAAI,CAAnB,EAAsB4D,GAAtB,EAA2B;YACrBA,CAAJ,IAASmX,GAAGnX,IAAI,CAAP,IAAYmX,GAAGnX,CAAH,CAArB;YACIA,CAAJ,IAASkX,GAAGlX,IAAI,CAAP,IAAYkX,GAAGlX,CAAH,CAArB;WACGA,CAAH,IAAQsX,IAAItX,CAAJ,IAASuX,IAAIvX,CAAJ,CAAjB;;;;;;SAMC,CAAH,IAAQqX,GAAG,CAAH,CAAR;SACGjb,IAAI,CAAP,IAAYib,GAAGjb,IAAI,CAAP,CAAZ;;WAEI4D,IAAI,CAAR,EAAWA,IAAI5D,IAAI,CAAnB,EAAsB4D,GAAtB,EAA2B;YACtBqX,GAAGrX,CAAH,MAAU,CAAV,IAAeqX,GAAGrX,IAAI,CAAP,MAAc,CAA7B,IAAmCqX,GAAGrX,IAAI,CAAP,IAAY,CAAb,KAAqBqX,GAAGrX,CAAH,IAAQ,CAAlE,EAAsE;aACjEA,CAAH,IAAQ,CAAR;SADF,MAEO;aACFA,CAAH,IAAQ,KAAKuX,IAAIvX,IAAI,CAAR,IAAauX,IAAIvX,CAAJ,CAAlB,KACN,CAAC,IAAIuX,IAAIvX,CAAJ,CAAJ,GAAauX,IAAIvX,IAAI,CAAR,CAAd,IAA4BqX,GAAGrX,IAAI,CAAP,CAA5B,GACA,CAACuX,IAAIvX,CAAJ,IAAS,IAAIuX,IAAIvX,IAAI,CAAR,CAAd,IAA4BqX,GAAGrX,CAAH,CAFtB,CAAR;;cAIG,CAACvE,SAAS2b,GAAGpX,CAAH,CAAT,CAAJ,EAAqB;eAChBA,CAAH,IAAQ,CAAR;;;;;;;aAOC,IAAIsU,OAAJ,GAAc6B,IAAd,CAAmBe,GAAG,CAAH,CAAnB,EAA0BC,GAAG,CAAH,CAA1B,EAAiC,KAAjC,EAAwCtU,UAAU,CAAV,CAAxC,CAAP;;WAEI7C,IAAI,CAAR,EAAWA,IAAI5D,IAAI,CAAnB,EAAsB4D,GAAtB,EAA2B;aACpB0W,KAAL;;WAEK1W,CAAH,IAAQuX,IAAIvX,CAAJ,IAAS,CAFnB,EAGEmX,GAAGnX,CAAH,IAAQoX,GAAGpX,CAAH,IAAQuX,IAAIvX,CAAJ,CAAR,GAAiB,CAH3B;;WAKKA,IAAI,CAAP,IAAYuX,IAAIvX,CAAJ,IAAS,CALvB,EAMEmX,GAAGnX,IAAI,CAAP,IAAYoX,GAAGpX,IAAI,CAAP,IAAYuX,IAAIvX,CAAJ,CAAZ,GAAqB,CANnC;;WAQKA,IAAI,CAAP,CARF,EASEmX,GAAGnX,IAAI,CAAP,CATF,EAWE,KAXF,EAYE6C,UAAU7C,IAAI,CAAd,CAZF;;;aAgBK0U,IAAP;;GAhGJ;;;;;;;;;;;;;ACzBF;;;;;AAKA,IAAM5R,iBAAiB;;SAEd;;YAEG,EAFH;;cAIK,KAJL;;iBAMQ;SACR,CADQ;SAER;KARA;;eAWM,IAXN;;cAaK,IAbL;;2BAekBvG,IAflB;;UAiBCX;GAnBa;;SAsBd;;YAEG,EAFH;;cAIK,OAJL;;iBAMQ;SACR,CADQ;SAER;KARA;;eAWM,IAXN;;cAaK,IAbL;;2BAekBW,IAflB;;UAiBCX,SAjBD;;mBAmBU,EAnBV;;iBAqBQ;GA3CM;;SA8CdA,SA9Cc;;UAgDbA,SAhDa;;YAkDX,IAlDW;;aAoDV,IApDU;;YAsDX,KAtDW;;YAwDX,CAxDW;;cA0DT,IA1DS;;sBA4DD,KA5DC;;OA8DhBA,SA9DgB;;QAgEfA,SAhEe;;gBAkEP;SACP,EADO;WAEL,EAFK;YAGJ,CAHI;UAIN;GAtEa;;aAyEV,KAzEU;;eA2ER,KA3EQ;;cA6ET;WACH,eADG;WAEH,UAFG;gBAGE,WAHF;YAIF,WAJE;UAKJ,SALI;WAMH,UANG;UAOJ,SAPI;UAQJ,SARI;eASC,UATD;oBAUM,oBAVN;cAWA,aAXA;gBAYE,eAZF;WAaH,UAbG;SAcL;;CA3FT;;AA+FA,IAAa4b,SAAb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkFcxc,KAAZ,EAAmBsF,IAAnB,EAAyBkC,OAAzB,EAAkC+L,iBAAlC,EAAqD;;;iHAC7CvT,KAD6C,EACtCsF,IADsC,EAChCwC,cADgC,EAChBhD,OAAO,EAAP,EAAWgD,cAAX,EAA2BN,OAA3B,CADgB,EACqB+L,iBADrB;;;;;;;;;;;gCAQzC/L,OA1Fd,EA0FuB;UACflC,OAAOS,cAAc,KAAKT,IAAnB,EAAyBkC,QAAQR,WAAjC,EAA8C,IAA9C,CAAX;;;WAGK8E,GAAL,GAAW8E,UAAU,KAAKtD,SAAf,EAA0B9F,QAAQmH,KAAlC,EAAyCnH,QAAQkH,MAAjD,EAAyDlH,QAAQ6P,UAAR,CAAmBoF,KAA5E,CAAX;;UAEI7J,YAAY,KAAK9G,GAAL,CAAS6B,IAAT,CAAc,GAAd,EAAmB1B,QAAnB,CAA4BzE,QAAQ6P,UAAR,CAAmBzE,SAA/C,CAAhB;UACI8J,cAAc,KAAK5Q,GAAL,CAAS6B,IAAT,CAAc,GAAd,CAAlB;UACIgJ,aAAa,KAAK7K,GAAL,CAAS6B,IAAT,CAAc,GAAd,EAAmB1B,QAAnB,CAA4BzE,QAAQ6P,UAAR,CAAmBV,UAA/C,CAAjB;;UAEI3E,YAAYV,gBAAgB,KAAKxF,GAArB,EAA0BtE,OAA1B,EAAmCM,eAAekJ,OAAlD,CAAhB;UACIS,KAAJ,EAAWC,KAAX;;UAEGlK,QAAQiK,KAAR,CAAckL,IAAd,KAAuB/b,SAA1B,EAAqC;gBAC3B,IAAI4X,QAAJ,CAAapC,UAAUnS,CAAvB,EAA0BqB,KAAKc,UAAL,CAAgBC,MAA1C,EAAkD2L,SAAlD,EAA6DlN,OAAO,EAAP,EAAW0C,QAAQiK,KAAnB,EAA0B;iBACtFnM,KAAKc,UAAL,CAAgBI,MADsE;mBAEpFgB,QAAQoV;SAFkD,CAA7D,CAAR;OADF,MAKO;gBACG,IAAIpV,QAAQiK,KAAR,CAAckL,IAAlB,CAAuBvG,UAAUnS,CAAjC,EAAoCqB,KAAKc,UAAL,CAAgBC,MAApD,EAA4D2L,SAA5D,EAAuExK,QAAQiK,KAA/E,CAAR;;;UAGCjK,QAAQkK,KAAR,CAAciL,IAAd,KAAuB/b,SAA1B,EAAqC;gBAC3B,IAAIqX,aAAJ,CAAkB7B,UAAUjP,CAA5B,EAA+B7B,KAAKc,UAAL,CAAgBC,MAA/C,EAAuD2L,SAAvD,EAAkElN,OAAO,EAAP,EAAW0C,QAAQkK,KAAnB,EAA0B;gBAC5FnR,UAAUiH,QAAQc,IAAlB,IAA0Bd,QAAQc,IAAlC,GAAyCd,QAAQkK,KAAR,CAAcpJ,IADqC;eAE7F/H,UAAUiH,QAAQiB,GAAlB,IAAyBjB,QAAQiB,GAAjC,GAAuCjB,QAAQkK,KAAR,CAAcjJ;SAFc,CAAlE,CAAR;OADF,MAKO;gBACG,IAAIjB,QAAQkK,KAAR,CAAciL,IAAlB,CAAuBvG,UAAUjP,CAAjC,EAAoC7B,KAAKc,UAAL,CAAgBC,MAApD,EAA4D2L,SAA5D,EAAuExK,QAAQkK,KAA/E,CAAR;;;YAGImL,mBAAN,CAA0BjK,SAA1B,EAAqC+D,UAArC,EAAiD,KAAK9B,qBAAtD,EAA6ErN,OAA7E,EAAsF,KAAKsH,YAA3F;YACM+N,mBAAN,CAA0BjK,SAA1B,EAAqC+D,UAArC,EAAiD,KAAK9B,qBAAtD,EAA6ErN,OAA7E,EAAsF,KAAKsH,YAA3F;;UAEItH,QAAQsV,kBAAZ,EAAgC;6BACTlK,SAArB,EAAgCZ,SAAhC,EAA2CxK,QAAQ6P,UAAR,CAAmBxE,cAA9D,EAA8E,KAAK/D,YAAnF;;;;WAIGiO,GAAL,CAAS1W,MAAT,CAAgBzD,OAAhB,CAAwB,UAASyD,MAAT,EAAiB2W,WAAjB,EAA8B;YAChDC,gBAAgBP,YAAY/O,IAAZ,CAAiB,GAAjB,CAApB;;;sBAGc5B,IAAd,CAAmB;4BACC1F,OAAOoB,IADR;qBAENpC,UAAUgB,OAAOQ,IAAjB;SAFb;;;sBAMcoF,QAAd,CAAuB,CACrBzE,QAAQ6P,UAAR,CAAmBhR,MADE,EAEpBA,OAAOmF,SAAP,IAAoBhE,QAAQ6P,UAAR,CAAmBhR,MAAnB,GAA4B,GAA5B,GAAkClF,cAAc6b,WAAd,CAFlC,EAGrBzO,IAHqB,CAGhB,GAHgB,CAAvB;;YAKI3G,kBAAkB,EAAtB;YACEsV,WAAW,EADb;;aAGK9W,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,EAAoCpa,OAApC,CAA4C,UAASpC,KAAT,EAAgB2c,UAAhB,EAA4B;cAClErZ,IAAI;eACHkO,UAAU9N,EAAV,GAAeuN,MAAMsF,YAAN,CAAmBvW,KAAnB,EAA0B2c,UAA1B,EAAsC7X,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAAtC,CADZ;eAEHhL,UAAUC,EAAV,GAAeP,MAAMqF,YAAN,CAAmBvW,KAAnB,EAA0B2c,UAA1B,EAAsC7X,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAAtC;WAFpB;0BAIgBrW,IAAhB,CAAqB7C,EAAEG,CAAvB,EAA0BH,EAAEqD,CAA5B;mBACSR,IAAT,CAAc;mBACLnG,KADK;wBAEA2c,UAFA;kBAGNvW,YAAYP,MAAZ,EAAoB8W,UAApB;WAHR;SAN0C,CAW1CvQ,IAX0C,CAWrC,IAXqC,CAA5C;;YAaIlF,gBAAgB;sBACNH,gBAAgBlB,MAAhB,EAAwBmB,OAAxB,EAAiC,YAAjC,CADM;qBAEPD,gBAAgBlB,MAAhB,EAAwBmB,OAAxB,EAAiC,WAAjC,CAFO;oBAGRD,gBAAgBlB,MAAhB,EAAwBmB,OAAxB,EAAiC,UAAjC,CAHQ;oBAIRD,gBAAgBlB,MAAhB,EAAwBmB,OAAxB,EAAiC,UAAjC,CAJQ;oBAKRD,gBAAgBlB,MAAhB,EAAwBmB,OAAxB,EAAiC,UAAjC;SALZ;;YAQI4V,YAAY,OAAO1V,cAAc2V,UAArB,KAAoC,UAApC,GACd3V,cAAc2V,UADA,GACc3V,cAAc2V,UAAd,GAA2BpB,eAA3B,GAA6ClB,MAD3E;;;YAIIrB,OAAO0D,UAAUxV,eAAV,EAA2BsV,QAA3B,CAAX;;;;;YAKIxV,cAAc4V,SAAlB,EAA6B;;eAEtBxE,YAAL,CAAkBlW,OAAlB,CAA0B,UAASoW,WAAT,EAAsB;gBAC1CuE,QAAQN,cAActP,IAAd,CAAmB,MAAnB,EAA2B;kBACjCqL,YAAY/U,CADqB;kBAEjC+U,YAAY7R,CAFqB;kBAGjC6R,YAAY/U,CAAZ,GAAgB,IAHiB;kBAIjC+U,YAAY7R;aAJN,EAKTK,QAAQ6P,UAAR,CAAmBkG,KALV,EAKiBxR,IALjB,CAKsB;0BACpB,CAACiN,YAAY1T,IAAZ,CAAiB9E,KAAjB,CAAuByD,CAAxB,EAA2B+U,YAAY1T,IAAZ,CAAiB9E,KAAjB,CAAuB2G,CAAlD,EAAqD+D,MAArD,CAA4D3K,SAA5D,EAAuEgO,IAAvE,CAA4E,GAA5E,CADoB;yBAErBlJ,UAAU2T,YAAY1T,IAAZ,CAAiBuB,IAA3B;aAPD,CAAZ;;iBAUKiI,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+B;oBACvB,OADuB;qBAEtB0I,YAAY1T,IAAZ,CAAiB9E,KAFK;qBAGtBwY,YAAY1T,IAAZ,CAAiB6X,UAHK;oBAIvBnE,YAAY1T,IAAZ,CAAiBuB,IAJM;sBAKrBR,MALqB;2BAMhB2W,WANgB;qBAOtBvL,KAPsB;qBAQtBC,KARsB;qBAStBuL,aATsB;uBAUpBM,KAVoB;iBAW1BvE,YAAY/U,CAXc;iBAY1B+U,YAAY7R;aAZjB;WAXwB,CAyBxByF,IAzBwB,CAyBnB,IAzBmB,CAA1B;;;YA4BClF,cAAc8V,QAAjB,EAA2B;cACrBpC,OAAO6B,cAActP,IAAd,CAAmB,MAAnB,EAA2B;eACjC+L,KAAKlU,SAAL;WADM,EAERgC,QAAQ6P,UAAR,CAAmB+D,IAFX,EAEiB,IAFjB,CAAX;;eAIKtM,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+B;kBACvB,MADuB;oBAErBhL,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAFqB;kBAGvBtD,KAAK+D,KAAL,EAHuB;uBAIlBzL,SAJkB;mBAKtBgL,WALsB;oBAMrB3W,MANqB;yBAOhB2W,WAPgB;wBAQjB3W,OAAOQ,IARU;mBAStB4K,KATsB;mBAUtBC,KAVsB;mBAWtBuL,aAXsB;qBAYpB7B;WAZX;;;;YAiBC1T,cAAcgW,QAAd,IAA0BhM,MAAMnO,KAAnC,EAA0C;;;cAGpCoa,WAAWnb,KAAKC,GAAL,CAASD,KAAKsG,GAAL,CAASpB,cAAciW,QAAvB,EAAiCjM,MAAMnO,KAAN,CAAYd,GAA7C,CAAT,EAA4DiP,MAAMnO,KAAN,CAAYuF,GAAxE,CAAf;;;cAGI8U,oBAAoB5L,UAAUC,EAAV,GAAeP,MAAMqF,YAAN,CAAmB4G,QAAnB,CAAvC;;;eAGKE,cAAL,CAAoB,GAApB,EAAyB3S,MAAzB,CAAgC,SAAS4S,iBAAT,CAA2BC,WAA3B,EAAwC;;mBAE/DA,YAAYjF,YAAZ,CAAyBrX,MAAzB,GAAkC,CAAzC;WAFF,EAGGiB,GAHH,CAGO,SAASsb,aAAT,CAAuBC,iBAAvB,EAA0C;;gBAE3CC,eAAeD,kBAAkBnF,YAAlB,CAA+B,CAA/B,CAAnB;gBACIqF,cAAcF,kBAAkBnF,YAAlB,CAA+BmF,kBAAkBnF,YAAlB,CAA+BrX,MAA/B,GAAwC,CAAvE,CAAlB;;;;;;mBAMOwc,kBAAkBR,KAAlB,CAAwB,IAAxB,EACJtL,QADI,CACK,CADL,EAEJhC,MAFI,CAEG,CAFH,EAGJgL,IAHI,CAGC+C,aAAaja,CAHd,EAGiB2Z,iBAHjB,EAIJxC,IAJI,CAIC8C,aAAaja,CAJd,EAIiBia,aAAa/W,CAJ9B,EAKJgL,QALI,CAKK8L,kBAAkBnF,YAAlB,CAA+BrX,MAA/B,GAAwC,CAL7C,EAMJ2Z,IANI,CAMC+C,YAAYla,CANb,EAMgB2Z,iBANhB,CAAP;WAZF,EAoBGhb,OApBH,CAoBW,SAASwb,UAAT,CAAoBC,QAApB,EAA8B;;;gBAGnCC,OAAOrB,cAActP,IAAd,CAAmB,MAAnB,EAA2B;iBACjC0Q,SAAS7Y,SAAT;aADM,EAERgC,QAAQ6P,UAAR,CAAmBiH,IAFX,EAEiB,IAFjB,CAAX;;;iBAKKxP,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+B;oBACvB,MADuB;sBAErBhL,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAFqB;oBAGvBqB,SAASZ,KAAT,EAHuB;sBAIrBpX,MAJqB;2BAKhB2W,WALgB;qBAMtBvL,KANsB;qBAOtBC,KAPsB;yBAQlBM,SARkB;qBAStBgL,WATsB;qBAUtBC,aAVsB;uBAWpBqB;aAXX;WARS,CAqBT1R,IArBS,CAqBJ,IArBI,CApBX;;OA7GoB,CAwJtBA,IAxJsB,CAwJjB,IAxJiB,CAAxB;;WA0JKkC,YAAL,CAAkBwB,IAAlB,CAAuB,SAAvB,EAAkC;gBACxBoB,MAAMpO,MADkB;mBAErB0O,SAFqB;eAGzBP,KAHyB;eAIzBC,KAJyB;aAK3B,KAAK5F,GALsB;iBAMvBtE;OANX;;;;;EA3R2BoN,SAA/B;;ACrGA;;;;;AAKA,IAAM9M,mBAAiB;;SAEd;;YAEG,EAFH;;cAIK,KAJL;;iBAMQ;SACR,CADQ;SAER;KARA;;eAWM,IAXN;;cAaK,IAbL;;2BAekBvG,IAflB;;mBAiBU,EAjBV;;iBAmBQ;GArBM;;SAwBd;;YAEG,EAFH;;cAIK,OAJL;;iBAMQ;SACR,CADQ;SAER;KARA;;eAWM,IAXN;;cAaK,IAbL;;2BAekBA,IAflB;;mBAiBU,EAjBV;;iBAmBQ;GA3CM;;SA8CdX,SA9Cc;;UAgDbA,SAhDa;;QAkDfA,SAlDe;;OAoDhBA,SApDgB;;kBAsDL,CAtDK;;gBAwDP;SACP,EADO;WAEL,EAFK;YAGJ,CAHI;UAIN;GA5Da;;qBA+DF,EA/DE;;aAiEV,KAjEU;;;aAoEV,YApEU;;kBAsEL,KAtEK;;oBAwEH,KAxEG;;eA0ER,KA1EQ;;sBA4ED,KA5EC;;cA8ET;WACH,cADG;oBAEM,oBAFN;WAGH,UAHG;gBAIE,WAJF;YAKF,WALE;SAML,QANK;UAOJ,SAPI;eAQC,UARD;oBASM,oBATN;cAUA,aAVA;gBAWE,eAXF;WAYH,UAZG;SAaL;;CA3FT;;AA+FA,IAAa2d,QAAb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAsCcve,KAAZ,EAAmBsF,IAAnB,EAAyBkC,OAAzB,EAAkC+L,iBAAlC,EAAqD;;;+GAC7CvT,KAD6C,EACtCsF,IADsC,EAChCwC,gBADgC,EAChBhD,OAAO,EAAP,EAAWgD,gBAAX,EAA2BN,OAA3B,CADgB,EACqB+L,iBADrB;;;;;;;;;;;gCAQzC/L,OA9Cd,EA8CuB;UACflC,IAAJ;UACI+C,OAAJ;;UAEGb,QAAQgX,gBAAX,EAA6B;eACpBzY,cAAc,KAAKT,IAAnB,EAAyBkC,QAAQR,WAAjC,EAA8CQ,QAAQiX,cAAR,GAAyB,GAAzB,GAA+B,GAA7E,CAAP;aACKrY,UAAL,CAAgBC,MAAhB,GAAyBf,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB3D,GAAvB,CAA2B,UAASlC,KAAT,EAAgB;iBAC3D,CAACA,KAAD,CAAP;SADuB,CAAzB;OAFF,MAKO;eACEuF,cAAc,KAAKT,IAAnB,EAAyBkC,QAAQR,WAAjC,EAA8CQ,QAAQiX,cAAR,GAAyB,GAAzB,GAA+B,GAA7E,CAAP;;;;WAIG3S,GAAL,GAAW8E,UACT,KAAKtD,SADI,EAET9F,QAAQmH,KAFC,EAGTnH,QAAQkH,MAHC,EAITlH,QAAQ6P,UAAR,CAAmBoF,KAAnB,IAA4BjV,QAAQiX,cAAR,GAAyB,MAAMjX,QAAQ6P,UAAR,CAAmBoH,cAAlD,GAAmE,EAA/F,CAJS,CAAX;;;UAQI7L,YAAY,KAAK9G,GAAL,CAAS6B,IAAT,CAAc,GAAd,EAAmB1B,QAAnB,CAA4BzE,QAAQ6P,UAAR,CAAmBzE,SAA/C,CAAhB;UACI8J,cAAc,KAAK5Q,GAAL,CAAS6B,IAAT,CAAc,GAAd,CAAlB;UACIgJ,aAAa,KAAK7K,GAAL,CAAS6B,IAAT,CAAc,GAAd,EAAmB1B,QAAnB,CAA4BzE,QAAQ6P,UAAR,CAAmBV,UAA/C,CAAjB;;UAEGnP,QAAQkX,SAAR,IAAqBpZ,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB5E,MAAvB,KAAkC,CAA1D,EAA6D;;;YAGvDkd,aAAavc,UAAUkD,KAAKc,UAAL,CAAgBC,MAA1B,EAAkC,SAASsY,UAAT,GAAsB;iBAChEjd,MAAMgF,SAAN,CAAgBD,KAAhB,CAAsB4E,IAAtB,CAA2BlG,SAA3B,EAAsCzC,GAAtC,CAA0C,UAASlC,KAAT,EAAgB;mBACxDA,KAAP;WADK,EAEJmF,MAFI,CAEG,UAASiZ,IAAT,EAAeC,IAAf,EAAqB;mBACtB;iBACFD,KAAK3a,CAAL,IAAU4a,QAAQA,KAAK5a,CAAvB,KAA6B,CAD3B;iBAEF2a,KAAKzX,CAAL,IAAU0X,QAAQA,KAAK1X,CAAvB,KAA6B;aAFlC;WAHK,EAOJ,EAAClD,GAAG,CAAJ,EAAOkD,GAAG,CAAV,EAPI,CAAP;SADe,CAAjB;;kBAWUgB,WAAW,CAACwW,UAAD,CAAX,EAAyBnX,OAAzB,EAAkCA,QAAQiX,cAAR,GAAyB,GAAzB,GAA+B,GAAjE,CAAV;OAdF,MAgBO;;kBAEKtW,WAAW7C,KAAKc,UAAL,CAAgBC,MAA3B,EAAmCmB,OAAnC,EAA4CA,QAAQiX,cAAR,GAAyB,GAAzB,GAA+B,GAA3E,CAAV;;;;cAIMnW,IAAR,GAAe,CAACd,QAAQc,IAAT,KAAkBd,QAAQc,IAAR,KAAiB,CAAjB,GAAqB,CAArB,GAAyBD,QAAQC,IAAnD,CAAf;cACQG,GAAR,GAAc,CAACjB,QAAQiB,GAAT,KAAiBjB,QAAQiB,GAAR,KAAgB,CAAhB,GAAoB,CAApB,GAAwBJ,QAAQI,GAAjD,CAAd;;UAEIuJ,YAAYV,gBAAgB,KAAKxF,GAArB,EAA0BtE,OAA1B,EAAmCM,iBAAekJ,OAAlD,CAAhB;;UAEI8N,SAAJ,EACEC,cADF,EAEEC,SAFF,EAGEvN,KAHF,EAIEC,KAJF;;;UAOGlK,QAAQgX,gBAAR,IAA4BhX,QAAQkX,SAAvC,EAAkD;;;yBAG/BpZ,KAAKc,UAAL,CAAgBI,MAAhB,CAAuBC,KAAvB,CAA6B,CAA7B,EAAgC,CAAhC,CAAjB;OAHF,MAIO;;;;yBAIYnB,KAAKc,UAAL,CAAgBI,MAAjC;;;;UAICgB,QAAQiX,cAAX,EAA2B;YACtBjX,QAAQiK,KAAR,CAAckL,IAAd,KAAuB/b,SAA1B,EAAqC;sBACvB6Q,QAAQ,IAAIwG,aAAJ,CAAkB7B,UAAUnS,CAA5B,EAA+BqB,KAAKc,UAAL,CAAgBC,MAA/C,EAAuD2L,SAAvD,EAAkElN,OAAO,EAAP,EAAW0C,QAAQiK,KAAnB,EAA0B;qBACrGpJ,OADqG;4BAE9F;WAFoE,CAAlE,CAApB;SADF,MAKO;sBACOoJ,QAAQ,IAAIjK,QAAQiK,KAAR,CAAckL,IAAlB,CAAuBvG,UAAUnS,CAAjC,EAAoCqB,KAAKc,UAAL,CAAgBC,MAApD,EAA4D2L,SAA5D,EAAuElN,OAAO,EAAP,EAAW0C,QAAQiK,KAAnB,EAA0B;qBAC1GpJ,OAD0G;4BAEnG;WAFyE,CAAvE,CAApB;;;YAMCb,QAAQkK,KAAR,CAAciL,IAAd,KAAuB/b,SAA1B,EAAqC;sBACvB8Q,QAAQ,IAAI8G,QAAJ,CAAapC,UAAUjP,CAAvB,EAA0B7B,KAAKc,UAAL,CAAgBC,MAA1C,EAAkD2L,SAAlD,EAA6D;mBACxE+M;WADW,CAApB;SADF,MAIO;sBACOrN,QAAQ,IAAIlK,QAAQkK,KAAR,CAAciL,IAAlB,CAAuBvG,UAAUjP,CAAjC,EAAoC7B,KAAKc,UAAL,CAAgBC,MAApD,EAA4D2L,SAA5D,EAAuExK,QAAQkK,KAA/E,CAApB;;OAlBJ,MAoBO;YACFlK,QAAQiK,KAAR,CAAckL,IAAd,KAAuB/b,SAA1B,EAAqC;sBACvB6Q,QAAQ,IAAI+G,QAAJ,CAAapC,UAAUnS,CAAvB,EAA0BqB,KAAKc,UAAL,CAAgBC,MAA1C,EAAkD2L,SAAlD,EAA6D;mBACxE+M;WADW,CAApB;SADF,MAIO;sBACOtN,QAAQ,IAAIjK,QAAQiK,KAAR,CAAckL,IAAlB,CAAuBvG,UAAUnS,CAAjC,EAAoCqB,KAAKc,UAAL,CAAgBC,MAApD,EAA4D2L,SAA5D,EAAuExK,QAAQiK,KAA/E,CAApB;;;YAGCjK,QAAQkK,KAAR,CAAciL,IAAd,KAAuB/b,SAA1B,EAAqC;sBACvB8Q,QAAQ,IAAIuG,aAAJ,CAAkB7B,UAAUjP,CAA5B,EAA+B7B,KAAKc,UAAL,CAAgBC,MAA/C,EAAuD2L,SAAvD,EAAkElN,OAAO,EAAP,EAAW0C,QAAQkK,KAAnB,EAA0B;qBACrGrJ,OADqG;4BAE9F;WAFoE,CAAlE,CAApB;SADF,MAKO;sBACOqJ,QAAQ,IAAIlK,QAAQkK,KAAR,CAAciL,IAAlB,CAAuBvG,UAAU5D,KAAV,CAAgBrL,CAAvC,EAA0C7B,KAAKc,UAAL,CAAgBC,MAA1D,EAAkE2L,SAAlE,EAA6ElN,OAAO,EAAP,EAAW0C,QAAQkK,KAAnB,EAA0B;qBAChHrJ,OADgH;4BAEzG;WAF+E,CAA7E,CAApB;;;;;UAQA4W,YAAYzX,QAAQiX,cAAR,GAA0BzM,UAAU9N,EAAV,GAAe4a,UAAU/H,YAAV,CAAuB,CAAvB,CAAzC,GAAuE/E,UAAUC,EAAV,GAAe6M,UAAU/H,YAAV,CAAuB,CAAvB,CAAtG;;UAEImI,mBAAmB,EAAvB;;gBAEUrC,mBAAV,CAA8BjK,SAA9B,EAAyC+D,UAAzC,EAAqD,KAAK9B,qBAA1D,EAAiFrN,OAAjF,EAA0F,KAAKsH,YAA/F;gBACU+N,mBAAV,CAA8BjK,SAA9B,EAAyC+D,UAAzC,EAAqD,KAAK9B,qBAA1D,EAAiFrN,OAAjF,EAA0F,KAAKsH,YAA/F;;UAEItH,QAAQsV,kBAAZ,EAAgC;6BACTlK,SAArB,EAAgCZ,SAAhC,EAA2CxK,QAAQ6P,UAAR,CAAmBxE,cAA9D,EAA8E,KAAK/D,YAAnF;;;;WAIGiO,GAAL,CAAS1W,MAAT,CAAgBzD,OAAhB,CAAwB,UAASyD,MAAT,EAAiB2W,WAAjB,EAA8B;;YAEhDmC,QAAQnC,cAAc,CAAC1X,KAAKyX,GAAL,CAAS1W,MAAT,CAAgB5E,MAAhB,GAAyB,CAA1B,IAA+B,CAAzD;;YAEI2d,gBAAJ;;YAEInC,aAAJ;;;YAGGzV,QAAQgX,gBAAR,IAA4B,CAAChX,QAAQkX,SAAxC,EAAmD;;;6BAG9BM,UAAU3b,UAAV,GAAuBiC,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB5E,MAA9C,GAAuD,CAA1E;SAHF,MAIO,IAAG+F,QAAQgX,gBAAR,IAA4BhX,QAAQkX,SAAvC,EAAkD;;;6BAGpCM,UAAU3b,UAAV,GAAuB,CAA1C;SAHK,MAIA;;6BAEc2b,UAAU3b,UAAV,GAAuBiC,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,EAAoCvb,MAA3D,GAAoE,CAAvF;;;;wBAIcib,YAAY/O,IAAZ,CAAiB,GAAjB,CAAhB;;;sBAGc5B,IAAd,CAAmB;4BACC1F,OAAOoB,IADR;qBAENpC,UAAUgB,OAAOQ,IAAjB;SAFb;;;sBAMcoF,QAAd,CAAuB,CACrBzE,QAAQ6P,UAAR,CAAmBhR,MADE,EAEpBA,OAAOmF,SAAP,IAAoBhE,QAAQ6P,UAAR,CAAmBhR,MAAnB,GAA4B,GAA5B,GAAkClF,cAAc6b,WAAd,CAFlC,EAGrBzO,IAHqB,CAGhB,GAHgB,CAAvB;;aAKKnI,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,EAAoCpa,OAApC,CAA4C,UAASpC,KAAT,EAAgB2c,UAAhB,EAA4B;cAClEkC,SAAJ,EACEC,GADF,EAEEC,aAFF,EAGEC,mBAHF;;;cAMGhY,QAAQgX,gBAAR,IAA4B,CAAChX,QAAQkX,SAAxC,EAAmD;;;kCAG3B1B,WAAtB;WAHF,MAIO,IAAGxV,QAAQgX,gBAAR,IAA4BhX,QAAQkX,SAAvC,EAAkD;;;kCAGjC,CAAtB;WAHK,MAIA;;kCAEiBvB,UAAtB;;;;cAIC3V,QAAQiX,cAAX,EAA2B;wBACb;iBACPzM,UAAU9N,EAAV,GAAe4a,UAAU/H,YAAV,CAAuBvW,SAASA,MAAMyD,CAAf,GAAmBzD,MAAMyD,CAAzB,GAA6B,CAApD,EAAuDkZ,UAAvD,EAAmE7X,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAAnE,CADR;iBAEPhL,UAAUC,EAAV,GAAe+M,UAAUjI,YAAV,CAAuBvW,SAASA,MAAM2G,CAAf,GAAmB3G,MAAM2G,CAAzB,GAA6B,CAApD,EAAuDqY,mBAAvD,EAA4Ela,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAA5E;aAFpB;WADF,MAKO;wBACO;iBACPhL,UAAU9N,EAAV,GAAe8a,UAAUjI,YAAV,CAAuBvW,SAASA,MAAMyD,CAAf,GAAmBzD,MAAMyD,CAAzB,GAA6B,CAApD,EAAuDub,mBAAvD,EAA4Ela,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAA5E,CADR;iBAEPhL,UAAUC,EAAV,GAAe6M,UAAU/H,YAAV,CAAuBvW,SAASA,MAAM2G,CAAf,GAAmB3G,MAAM2G,CAAzB,GAA6B,CAApD,EAAuDgW,UAAvD,EAAmE7X,KAAKc,UAAL,CAAgBC,MAAhB,CAAuB2W,WAAvB,CAAnE;aAFpB;;;;;;;cAUCgC,qBAAqBxG,QAAxB,EAAkC;;gBAE7B,CAACwG,UAAUxX,OAAV,CAAkBkR,OAAtB,EAA+B;wBACnBsG,UAAUxM,KAAV,CAAgBnE,GAA1B,KAAkC+Q,oBAAoB5X,QAAQiX,cAAR,GAAyB,CAAC,CAA1B,GAA8B,CAAlD,CAAlC;;;sBAGQO,UAAUxM,KAAV,CAAgBnE,GAA1B,KAAmC7G,QAAQkX,SAAR,IAAqBlX,QAAQgX,gBAA9B,GAAkD,CAAlD,GAAsDW,QAAQ3X,QAAQiY,iBAAhB,IAAqCjY,QAAQiX,cAAR,GAAyB,CAAC,CAA1B,GAA8B,CAAnE,CAAxF;;;;0BAIcS,iBAAiB/B,UAAjB,KAAgC8B,SAAhD;2BACiB9B,UAAjB,IAA+BoC,iBAAiBN,YAAYI,UAAUL,UAAUvM,YAAV,CAAuBpE,GAAjC,CAA7B,CAA/B;;;cAGG7N,UAAUI,SAAb,EAAwB;;;;cAIpB8e,YAAY,EAAhB;oBACUV,UAAUxM,KAAV,CAAgBnE,GAAhB,GAAsB,GAAhC,IAAuCgR,UAAUL,UAAUxM,KAAV,CAAgBnE,GAA1B,CAAvC;oBACU2Q,UAAUxM,KAAV,CAAgBnE,GAAhB,GAAsB,GAAhC,IAAuCgR,UAAUL,UAAUxM,KAAV,CAAgBnE,GAA1B,CAAvC;;cAEG7G,QAAQkX,SAAR,KAAsBlX,QAAQmY,SAAR,KAAsB,YAAtB,IAAsC,CAACnY,QAAQmY,SAArE,CAAH,EAAoF;;;;;sBAKxEX,UAAUvM,YAAV,CAAuBpE,GAAvB,GAA6B,GAAvC,IAA8CkR,aAA9C;sBACUP,UAAUvM,YAAV,CAAuBpE,GAAvB,GAA6B,GAAvC,IAA8C6Q,iBAAiB/B,UAAjB,CAA9C;WANF,MAOO;;;sBAGK6B,UAAUvM,YAAV,CAAuBpE,GAAvB,GAA6B,GAAvC,IAA8C4Q,SAA9C;sBACUD,UAAUvM,YAAV,CAAuBpE,GAAvB,GAA6B,GAAvC,IAA8CgR,UAAUL,UAAUvM,YAAV,CAAuBpE,GAAjC,CAA9C;;;;oBAIQnK,EAAV,GAAe1B,KAAKsG,GAAL,CAAStG,KAAKC,GAAL,CAASid,UAAUxb,EAAnB,EAAuB8N,UAAU9N,EAAjC,CAAT,EAA+C8N,UAAU7N,EAAzD,CAAf;oBACUA,EAAV,GAAe3B,KAAKsG,GAAL,CAAStG,KAAKC,GAAL,CAASid,UAAUvb,EAAnB,EAAuB6N,UAAU9N,EAAjC,CAAT,EAA+C8N,UAAU7N,EAAzD,CAAf;oBACU8N,EAAV,GAAezP,KAAKsG,GAAL,CAAStG,KAAKC,GAAL,CAASid,UAAUzN,EAAnB,EAAuBD,UAAUE,EAAjC,CAAT,EAA+CF,UAAUC,EAAzD,CAAf;oBACUC,EAAV,GAAe1P,KAAKsG,GAAL,CAAStG,KAAKC,GAAL,CAASid,UAAUxN,EAAnB,EAAuBF,UAAUE,EAAjC,CAAT,EAA+CF,UAAUC,EAAzD,CAAf;;cAEI2N,WAAWhZ,YAAYP,MAAZ,EAAoB8W,UAApB,CAAf;;;gBAGMF,cAActP,IAAd,CAAmB,MAAnB,EAA2B+R,SAA3B,EAAsClY,QAAQ6P,UAAR,CAAmBiI,GAAzD,EAA8DvT,IAA9D,CAAmE;wBAC3D,CAACvL,MAAMyD,CAAP,EAAUzD,MAAM2G,CAAhB,EAAmB+D,MAAnB,CAA0B3K,SAA1B,EAAqCgO,IAArC,CAA0C,GAA1C,CAD2D;uBAE5DlJ,UAAUua,QAAV;WAFP,CAAN;;eAKK9Q,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+BxL,OAAO;kBAC9B,KAD8B;mBAE7BtE,KAF6B;mBAG7B2c,UAH6B;kBAI9ByC,QAJ8B;oBAK5BvZ,MAL4B;yBAMvB2W,WANuB;mBAO7BvL,KAP6B;mBAQ7BC,KAR6B;uBASzBM,SATyB;mBAU7BiL,aAV6B;qBAW3BqC;WAXoB,EAY5BI,SAZ4B,CAA/B;SAvF0C,CAoG1C9S,IApG0C,CAoGrC,IApGqC,CAA5C;OArCsB,CA0ItBA,IA1IsB,CA0IjB,IA1IiB,CAAxB;;WA4IKkC,YAAL,CAAkBwB,IAAlB,CAAuB,SAAvB,EAAkC;gBACxBwO,UAAUxb,MADc;mBAErB0O,SAFqB;eAGzBP,KAHyB;eAIzBC,KAJyB;aAK3B,KAAK5F,GALsB;iBAMvBtE;OANX;;;;;EAzT0BoN,SAA9B;;ACnGA;;;;;AAKA,IAAM9M,mBAAiB;;SAEdlH,SAFc;;UAIbA,SAJa;;gBAMP,CANO;;cAQT;cACA,cADA;gBAEE,gBAFF;YAGF,WAHE;cAIA,cAJA;gBAKE,gBALF;WAMH;GAdY;;cAiBT,CAjBS;;SAmBdA,SAnBc;;SAqBd,KArBc;;;cAwBT,EAxBS;;aA0BV,IA1BU;;eA4BR,CA5BQ;;iBA8BN,QA9BM;;yBAgCEW,IAhCF;;kBAkCL,SAlCK;;eAoCR,KApCQ;;qBAsCF;CAtCrB;;;;;;;;;;AAiDA,AAAO,SAASse,uBAAT,CAAiCC,MAAjC,EAAyCrI,KAAzC,EAAgDsI,SAAhD,EAA2D;MAC5DC,aAAavI,MAAMxT,CAAN,GAAU6b,OAAO7b,CAAlC;;MAEI+b,cAAcD,cAAc,SAA5B,IACF,CAACC,UAAD,IAAeD,cAAc,SAD/B,EAC0C;WACjC,OAAP;GAFF,MAGO,IAAIC,cAAcD,cAAc,SAA5B,IACT,CAACC,UAAD,IAAeD,cAAc,SADxB,EACmC;WACjC,KAAP;GAFK,MAGA;WACE,QAAP;;;;AAIJ,IAAaE,QAAb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAqEcjgB,KAAZ,EAAmBsF,IAAnB,EAAyBkC,OAAzB,EAAkC+L,iBAAlC,EAAqD;;;+GAC7CvT,KAD6C,EACtCsF,IADsC,EAChCwC,gBADgC,EAChBhD,OAAO,EAAP,EAAWgD,gBAAX,EAA2BN,OAA3B,CADgB,EACqB+L,iBADrB;;;;;;;;;;;;gCASzC/L,OA9Ed,EA8EuB;UACflC,OAAOS,cAAc,KAAKT,IAAnB,CAAX;UACI4a,eAAe,EAAnB;UACEC,WADF;UAEEnO,SAFF;UAGExN,MAHF;UAIE4b,WAJF;UAKEC,YALF;UAMEC,aAAa9Y,QAAQ8Y,UANvB;;;WASKxU,GAAL,GAAW8E,UAAU,KAAKtD,SAAf,EAA0B9F,QAAQmH,KAAlC,EAAyCnH,QAAQkH,MAAjD,EAAyDlH,QAAQ+Y,KAAR,GAAgB/Y,QAAQ6P,UAAR,CAAmBmJ,UAAnC,GAAgDhZ,QAAQ6P,UAAR,CAAmBoJ,QAA5H,CAAX;;kBAEYnP,gBAAgB,KAAKxF,GAArB,EAA0BtE,OAA1B,EAAmCM,iBAAekJ,OAAlD,CAAZ;;eAESxO,KAAKsG,GAAL,CAASkJ,UAAUrD,KAAV,KAAoB,CAA7B,EAAgCqD,UAAUtD,MAAV,KAAqB,CAArD,CAAT;;qBAEelH,QAAQkZ,KAAR,IAAiBpb,KAAKc,UAAL,CAAgBC,MAAhB,CAAuBV,MAAvB,CAA8B,UAAUgb,aAAV,EAAyBC,YAAzB,EAAuC;eAC1FD,gBAAgBC,YAAvB;OAD4B,EAE3B,CAF2B,CAAhC;;UAIIC,aAAa9f,SAASyG,QAAQqZ,UAAjB,CAAjB;UACIA,WAAW/f,IAAX,KAAoB,GAAxB,EAA6B;mBAChBN,KAAX,IAAoBgE,SAAS,GAA7B;;;;;;gBAMQgD,QAAQ+Y,KAAR,GAAgBM,WAAWrgB,KAAX,GAAmB,CAAnC,GAAuC,CAAjD;;;;UAIIgH,QAAQsZ,aAAR,KAA0B,SAA1B,IAAuCtZ,QAAQ+Y,KAAnD,EAA0D;sBAC1C/b,MAAd;OADF,MAEO,IAAIgD,QAAQsZ,aAAR,KAA0B,QAA9B,EAAwC;;sBAE/B,CAAd;OAFK,MAGA;;;sBAGStc,SAAS,CAAvB;;;qBAGagD,QAAQwL,WAAvB;;;UAGI8M,SAAS;WACR9N,UAAU9N,EAAV,GAAe8N,UAAUrD,KAAV,KAAoB,CAD3B;WAERqD,UAAUE,EAAV,GAAeF,UAAUtD,MAAV,KAAqB;OAFzC;;;UAMIqS,uBAAuBzb,KAAKyX,GAAL,CAAS1W,MAAT,CAAgB6E,MAAhB,CAAuB,UAAU8V,GAAV,EAAe;eACtDA,IAAI1gB,cAAJ,CAAmB,OAAnB,IAA8B0gB,IAAIxgB,KAAJ,KAAc,CAA5C,GAAgDwgB,QAAQ,CAA/D;OADuB,EAEtBvf,MAFsB,KAEX,CAFhB;;;WAKKsb,GAAL,CAAS1W,MAAT,CAAgBzD,OAAhB,CAAwB,UAAUyD,MAAV,EAAkBxD,KAAlB,EAAyB;qBAClCA,KAAb,IAAsB,KAAKiJ,GAAL,CAAS6B,IAAT,CAAc,GAAd,EAAmB,IAAnB,EAAyB,IAAzB,CAAtB;OADsB,CAEtBf,IAFsB,CAEjB,IAFiB,CAAxB;;UAIIpF,QAAQgQ,SAAZ,EAAuB;sBACP,KAAK1L,GAAL,CAAS6B,IAAT,CAAc,GAAd,EAAmB,IAAnB,EAAyB,IAAzB,CAAd;;;;;WAKGoP,GAAL,CAAS1W,MAAT,CAAgBzD,OAAhB,CAAwB,UAAUyD,MAAV,EAAkBxD,KAAlB,EAAyB;;YAE3CyC,KAAKc,UAAL,CAAgBC,MAAhB,CAAuBxD,KAAvB,MAAkC,CAAlC,IAAuC2E,QAAQyZ,iBAAnD,EAAsE;;;qBAGzDpe,KAAb,EAAoBkJ,IAApB,CAAyB;4BACL1F,OAAOoB;SAD3B;;;qBAKa5E,KAAb,EAAoBoJ,QAApB,CAA6B,CAC3BzE,QAAQ6P,UAAR,CAAmBhR,MADQ,EAE1BA,OAAOmF,SAAP,IAAoBhE,QAAQ6P,UAAR,CAAmBhR,MAAnB,GAA4B,GAA5B,GAAkClF,cAAc0B,KAAd,CAF5B,EAG3B0L,IAH2B,CAGtB,GAHsB,CAA7B;;;YAMI2S,WAAYb,eAAe,CAAf,GAAmBC,aAAahb,KAAKc,UAAL,CAAgBC,MAAhB,CAAuBxD,KAAvB,IAAgCwd,YAAhC,GAA+C,GAA/E,GAAqF,CAArG;;;YAGIc,uBAAuB3e,KAAKC,GAAL,CAAS,CAAT,EAAY6d,cAAczd,UAAU,CAAV,IAAeke,oBAAf,GAAsC,CAAtC,GAA0C,GAAxD,CAAZ,CAA3B;;;;YAIIG,WAAWC,oBAAX,IAAmC,MAAvC,EAA+C;qBAClCA,uBAAuB,MAAlC;;;YAGEC,QAAQ/c,iBAAiByb,OAAO7b,CAAxB,EAA2B6b,OAAO3Y,CAAlC,EAAqC3C,MAArC,EAA6C2c,oBAA7C,CAAZ;YACEE,MAAMhd,iBAAiByb,OAAO7b,CAAxB,EAA2B6b,OAAO3Y,CAAlC,EAAqC3C,MAArC,EAA6C0c,QAA7C,CADR;;;YAIIxH,OAAO,IAAIJ,OAAJ,CAAY,CAAC9R,QAAQ+Y,KAArB,EACRpF,IADQ,CACHkG,IAAIpd,CADD,EACIod,IAAIla,CADR,EAERma,GAFQ,CAEJ9c,MAFI,EAEIA,MAFJ,EAEY,CAFZ,EAEe0c,WAAWZ,UAAX,GAAwB,GAFvC,EAE4C,CAF5C,EAE+Cc,MAAMnd,CAFrD,EAEwDmd,MAAMja,CAF9D,CAAX;;;YAKI,CAACK,QAAQ+Y,KAAb,EAAoB;eACbnF,IAAL,CAAU0E,OAAO7b,CAAjB,EAAoB6b,OAAO3Y,CAA3B;;;;;YAKE6R,cAAckH,aAAard,KAAb,EAAoB8K,IAApB,CAAyB,MAAzB,EAAiC;aAC9C+L,KAAKlU,SAAL;SADa,EAEfgC,QAAQ+Y,KAAR,GAAgB/Y,QAAQ6P,UAAR,CAAmBkK,UAAnC,GAAgD/Z,QAAQ6P,UAAR,CAAmBmK,QAFpD,CAAlB;;;oBAKYzV,IAAZ,CAAiB;sBACHzG,KAAKc,UAAL,CAAgBC,MAAhB,CAAuBxD,KAAvB,CADG;qBAEJwC,UAAUgB,OAAOQ,IAAjB;SAFb;;;YAMIW,QAAQ+Y,KAAZ,EAAmB;sBACLxU,IAAZ,CAAiB;qBACN,mBAAmB8U,WAAWrgB,KAA9B,GAAsC;WADjD;;;;aAMGsO,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+B;gBACvB,OADuB;iBAEtBhL,KAAKc,UAAL,CAAgBC,MAAhB,CAAuBxD,KAAvB,CAFsB;wBAGfwd,YAHe;iBAItBxd,KAJsB;gBAKvBwD,OAAOQ,IALgB;kBAMrBR,MANqB;iBAOtB6Z,aAAard,KAAb,CAPsB;mBAQpBmW,WARoB;gBASvBU,KAAK+D,KAAL,EATuB;kBAUrBqC,MAVqB;kBAWrBtb,MAXqB;sBAYjB8b,UAZiB;oBAanBY;SAbZ;;;YAiBI1Z,QAAQgQ,SAAZ,EAAuB;cACjBsJ,aAAJ;cACIxb,KAAKyX,GAAL,CAAS1W,MAAT,CAAgB5E,MAAhB,KAA2B,CAA/B,EAAkC;;4BAEhB;iBACXqe,OAAO7b,CADI;iBAEX6b,OAAO3Y;aAFZ;WAFF,MAMO;;4BAEW9C,iBACdyb,OAAO7b,CADO,EAEd6b,OAAO3Y,CAFO,EAGdiZ,WAHc,EAIdE,aAAa,CAACY,WAAWZ,UAAZ,IAA0B,CAJzB,CAAhB;;;cAQEmB,QAAJ;cACInc,KAAKc,UAAL,CAAgBI,MAAhB,IAA0B,CAAC9F,gBAAgB4E,KAAKc,UAAL,CAAgBI,MAAhB,CAAuB3D,KAAvB,CAAhB,CAA/B,EAA+E;uBAClEyC,KAAKc,UAAL,CAAgBI,MAAhB,CAAuB3D,KAAvB,CAAX;WADF,MAEO;uBACMyC,KAAKc,UAAL,CAAgBC,MAAhB,CAAuBxD,KAAvB,CAAX;;;cAGE6e,oBAAoBla,QAAQyP,qBAAR,CAA8BwK,QAA9B,EAAwC5e,KAAxC,CAAxB;;cAEI6e,qBAAqBA,sBAAsB,CAA/C,EAAkD;gBAC5CxO,eAAeiN,YAAYxS,IAAZ,CAAiB,MAAjB,EAAyB;kBACtCmT,cAAc7c,CADwB;kBAEtC6c,cAAc3Z,CAFwB;6BAG3B0Y,wBAAwBC,MAAxB,EAAgCgB,aAAhC,EAA+CtZ,QAAQma,cAAvD;aAHE,EAIhBna,QAAQ6P,UAAR,CAAmBI,KAJH,EAIUpE,IAJV,CAIe,KAAKqO,iBAJpB,CAAnB;;;iBAOK5S,YAAL,CAAkBwB,IAAlB,CAAuB,MAAvB,EAA+B;oBACvB,OADuB;qBAEtBzN,KAFsB;qBAGtBsd,WAHsB;uBAIpBjN,YAJoB;oBAKvB,KAAKwO,iBALkB;iBAM1BZ,cAAc7c,CANY;iBAO1B6c,cAAc3Z;aAPnB;;;;;;qBAcS+Z,QAAb;OA9HsB,CA+HtBtU,IA/HsB,CA+HjB,IA/HiB,CAAxB;;WAiIKkC,YAAL,CAAkBwB,IAAlB,CAAuB,SAAvB,EAAkC;mBACrB0B,SADqB;aAE3B,KAAKlG,GAFsB;iBAGvBtE;OAHX;;;;;EAnR0BoN,SAA9B","file":"chartist.esm.js"} \ No newline at end of file diff --git a/dist/chartist.min.css b/dist/chartist.min.css new file mode 100644 index 00000000..18dde681 --- /dev/null +++ b/dist/chartist.min.css @@ -0,0 +1,2 @@ +.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-ms-flexbox;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;-ms-flex-align:flex-end;align-items:flex-end}.ct-label.ct-horizontal.ct-end,.ct-label.ct-horizontal.ct-start{-webkit-box-pack: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;-ms-flex-align:flex-start;align-items:flex-start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack: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-pack:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left}.ct-chart-bar .ct-label.ct-horizontal.ct-start,.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-ms-flex-align:flex-end;align-items:flex-end;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end,.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;text-align:center}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack: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;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack: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;-ms-flex-align:center;align-items:center;-webkit-box-pack: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;-ms-flex-align:center;align-items:center;-webkit-box-pack: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-grid-background{fill:none}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{fill:none;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{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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.88889%}.ct-major-second:after{content:"";display:table;clear:both}.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.33333%}.ct-minor-third:after{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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.66667%}.ct-perfect-fifth:after{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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.8047%}.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{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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.33333%}.ct-major-seventh:after{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.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.33333%}.ct-major-twelfth:after{content:"";display:table;clear:both}.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{content:"";display:table;clear:both}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} +/*# sourceMappingURL=chartist.min.css.map */ \ No newline at end of file diff --git a/dist/chartist.min.css.map b/dist/chartist.min.css.map new file mode 100644 index 00000000..f51ef128 --- /dev/null +++ b/dist/chartist.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/styles/chartist.scss","src/styles/settings/_chartist-settings.scss"],"names":[],"mappings":"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","file":"chartist.min.css"} \ No newline at end of file diff --git a/dist/chartist.umd.js b/dist/chartist.umd.js new file mode 100644 index 00000000..ea9f9ab1 --- /dev/null +++ b/dist/chartist.umd.js @@ -0,0 +1,9 @@ +/* Chartist.js 1.0.0 + * Copyright © 2016 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){"object"==typeof exports&&"undefined"!=typeof module?b(exports):"function"==typeof define&&define.amd?define(["exports"],b):b(a.Chartist=a.Chartist||{})}(this,function(a){"use strict";function b(a,b,c){return a.replace(new RegExp(b,"g"),c)}function c(a){return a instanceof Node?a:document.querySelector(a)}function d(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)}function e(a){return null!==a&&isFinite(a)}function f(a){return!a&&0!==a}function g(a){return e(a)?+a:void 0}function h(a,b){return"number"==typeof a&&(a+=b),a}function i(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}}function j(a){return String.fromCharCode(97+a%26)}function k(a){return a}function l(a){return Array.apply(null,new Array(a))}function m(a,b){return a+(b?b:0)}function n(a){return function(b){return b*a}}function o(a){return function(b){return b+a}}function p(a,b){var c=[],d=Math.max.apply(null,a.map(function(a){return a.length}));return l(d).forEach(function(d,e){var f=a.map(function(a){return a[e]});c[e]=b.apply(null,f)}),c}function q(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)}function r(a,b,c){return b/c.range*a}function s(a,b){var c=Math.pow(10,b||c);return Math.round(a*c)/c}function t(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}function u(a,b,c,d){var e=(d-90)*Math.PI/180;return{x:a+c*Math.cos(e),y:b+c*Math.sin(e)}}function v(a){var b,c,d;for(a=a||{},b=1;b=2&&a[g]<=a[g-2]&&(f=!0),f&&(e.push({pathCoordinates:[],valueData:[]}),f=!1),e[e.length-1].pathCoordinates.push(a[g],a[g+1]),e[e.length-1].valueData.push(b[g/2]));return e}function H(a,b,c){function d(a){if(void 0!==a)if(a instanceof Array)for(var b=0;be.high&&(e.high=h),g&&h0?e.low=0:(e.high=1,e.low=0)),e}function I(a,b,c,d){function e(a,b){return a===(a+=b)&&(a*=1+(b>0?n:-n)),a}var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=q(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=r(a,j.step,j),l=k=c)j.step=1;else if(d&&m=c)j.step=m;else for(;;){if(l&&r(a,j.step,j)<=c)j.step*=2;else{if(l||!(r(a,j.step/2,j)>=c))break;if(j.step/=2,d&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var n=2.221e-16;for(j.step=Math.max(j.step,n),g=j.min,h=j.max;g+j.step<=j.low;)g=e(g,j.step);for(;h-j.step>=j.high;)h=e(h,-j.step);j.min=g,j.max=h,j.range=j.max-j.min;var o=[];for(f=j.min;f<=j.max;f=e(f,j.step)){var p=s(f);p!==o[o.length-1]&&o.push(f)}return j.values=o,j}function J(a){return document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#"+a,"1.1")}function K(a,b,c,d){var e;return b=b||"100%",c=c||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS($.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),e=new ea("svg").attr({width:b,height:c}).addClass(d).attr({style:"width: "+b+"; height: "+c+";"}),a.appendChild(e._node),e}function L(a,b){return b=b||0,"number"==typeof a?{top:a,right:a,bottom:a,left:a}:{top:"number"==typeof a.top?a.top:b,right:"number"==typeof a.right?a.right:b,bottom:"number"==typeof a.bottom?a.bottom:b,left:"number"==typeof a.left?a.left:b}}function M(a,b,c){var d=!(!b.axisX&&!b.axisY),e=d?b.axisY.offset:0,f=d?b.axisX.offset:0,g=a.width()||i(b.width).value||0,h=a.height()||i(b.height).value||0,j=L(b.chartPadding,c);g=Math.max(g,e+j.left+j.right),h=Math.max(h,f+j.top+j.bottom);var k={padding:j,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return d?("start"===b.axisX.position?(k.y2=j.top+f,k.y1=Math.max(h-j.bottom,k.y2+1)):(k.y2=j.top,k.y1=Math.max(h-j.bottom-f,k.y2+1)),"start"===b.axisY.position?(k.x1=j.left+e,k.x2=Math.max(g-j.right,k.x1+1)):(k.x1=j.left,k.x2=Math.max(g-j.right-e,k.x1+1))):(k.x1=j.left,k.x2=Math.max(g-j.right,k.x1+1),k.y2=j.top,k.y1=Math.max(h-j.bottom,k.y2+1)),k}function N(a,b,c,d,e,f,g,h){var i={};i[c.units.pos+"1"]=a,i[c.units.pos+"2"]=a,i[c.counterUnits.pos+"1"]=d,i[c.counterUnits.pos+"2"]=d+e;var j=f.elem("line",i,g.join(" "));h.emit("draw",v({type:"grid",axis:c,index:b,group:f,element:j},i))}function O(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})}function P(a,b,c,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=b,m[e.counterUnits.len]=Math.max(0,f-10),j){var n=''+d[c]+"";l=h.foreignObject(n,v({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[c]);k.emit("draw",v({type:"label",axis:e,index:c,group:h,element:l,text:d[c]},m))}function Q(a,b,c){function d(a){var d=f;if(f=v({},h),b)for(g=0;g1){var h=[];return g.forEach(function(a){h.push(b(a.pathCoordinates,a.valueData))}),sa.join(h)}if(e=g[0].pathCoordinates,f=g[0].valueData,e.length<=4)return T()(e,f);for(var i,j=(new sa).move(e[0],e[1],!1,f[0]),k=0,l=e.length;l-2*!i>k;k+=2){var m=[{x:+e[k-2],y:+e[k-1]},{x:+e[k],y:+e[k+1]},{x:+e[k+2],y:+e[k+3]},{x:+e[k+4],y:+e[k+5]}];i?k?l-4===k?m[3]={x:+e[0],y:+e[1]}:l-2===k&&(m[2]={x:+e[0],y:+e[1]},m[3]={x:+e[2],y:+e[3]}):m[0]={x:+e[l-2],y:+e[l-1]}:l-4===k?m[3]=m[2]:k||(m[0]={x:+e[k],y:+e[k+1]}),j.curve(c*(-m[0].x+6*m[1].x+m[2].x)/6+d*m[2].x,c*(-m[0].y+6*m[1].y+m[2].y)/6+d*m[2].y,c*(m[1].x+6*m[2].x-m[3].x)/6+d*m[2].x,c*(m[1].y+6*m[2].y-m[3].y)/6+d*m[2].y,m[2].x,m[2].y,!1,f[(k+2)/2])}return j}return T()([])}}function X(a){var b={fillHoles:!1};return a=v({},b,a),function b(c,d){var e=G(c,d,{fillHoles:a.fillHoles,increasingX:!0});if(e.length){if(e.length>1){var f=[];return e.forEach(function(a){f.push(b(a.pathCoordinates,a.valueData))}),sa.join(f)}if(c=e[0].pathCoordinates,d=e[0].valueData,c.length<=4)return T()(c,d);var g,h,i=[],j=[],k=c.length/2,l=[],m=[],n=[],o=[];for(g=0;g0!=m[g]>0?l[g]=0:(l[g]=3*(o[g-1]+o[g])/((2*o[g]+o[g-1])/m[g-1]+(o[g]+2*o[g-1])/m[g]),isFinite(l[g])||(l[g]=0));for(h=(new sa).move(i[0],j[0],!1,d[0]),g=0;ga.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}var Z="1.0.0",$={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"},_=8,aa={"&":"&","<":"<",">":">",'"':""","'":"'"},ba=function(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")},ca=function(){function a(a,b){for(var c=0;c1}).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,s).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,s)}).forEach(function(e){var g=k.elem("path",{d:e.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:b.normalized.series[h],path:e.clone(),series:f,seriesIndex:h,axisX:c,axisY:d,chartRect:i,index:h,group:k,element:g})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:d.bounds,chartRect:i,axisX:c,axisY:d,svg:this.svg,options:a})}}]),b}(ha),wa={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:k,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:k,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"}},xa=function(a){function b(a,c,d,e){return ba(this,b),ia(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,a,c,wa,v({},wa,d),e))}return ja(b,a),ca(b,[{key:"createChart",value:function(a){var b,c;a.distributeSeries?(b=y(this.data,a.reverseData,a.horizontalBars?"x":"y"),b.normalized.series=b.normalized.series.map(function(a){return[a]})):b=y(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=K(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var d=this.svg.elem("g").addClass(a.classNames.gridGroup),f=this.svg.elem("g"),g=this.svg.elem("g").addClass(a.classNames.labelGroup);if(a.stackBars&&0!==b.normalized.series.length){var h=p(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})});c=H([h],a,a.horizontalBars?"x":"y")}else c=H(b.normalized.series,a,a.horizontalBars?"x":"y");c.high=+a.high||(0===a.high?0:c.high),c.low=+a.low||(0===a.low?0:c.low);var i,k,l,m,n,o=M(this.svg,a,wa.padding);k=a.distributeSeries&&a.stackBars?b.normalized.labels.slice(0,1):b.normalized.labels,a.horizontalBars?(i=m=void 0===a.axisX.type?new na(ka.x,b.normalized.series,o,v({},a.axisX,{ +highLow:c,referenceValue:0})):new a.axisX.type(ka.x,b.normalized.series,o,v({},a.axisX,{highLow:c,referenceValue:0})),l=n=void 0===a.axisY.type?new pa(ka.y,b.normalized.series,o,{ticks:k}):new a.axisY.type(ka.y,b.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new pa(ka.x,b.normalized.series,o,{ticks:k}):new a.axisX.type(ka.x,b.normalized.series,o,a.axisX),i=n=void 0===a.axisY.type?new na(ka.y,b.normalized.series,o,v({},a.axisY,{highLow:c,referenceValue:0})):new a.axisY.type(ka.units.y,b.normalized.series,o,v({},a.axisY,{highLow:c,referenceValue:0})));var q=a.horizontalBars?o.x1+i.projectValue(0):o.y1-i.projectValue(0),r=[];l.createGridAndLabels(d,g,this.supportsForeignObject,a,this.eventEmitter),i.createGridAndLabels(d,g,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&O(d,o,a.classNames.gridBackground,this.eventEmitter),b.raw.series.forEach(function(c,d){var g,h,k=d-(b.raw.series.length-1)/2;g=a.distributeSeries&&!a.stackBars?l.axisLength/b.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/b.normalized.series[d].length/2,h=f.elem("g"),h.attr({"ct:series-name":c.name,"ct:meta":w(c.meta)}),h.addClass([a.classNames.series,c.className||a.classNames.series+"-"+j(d)].join(" ")),b.normalized.series[d].forEach(function(f,j){var p,s,t,u;if(u=a.distributeSeries&&!a.stackBars?d:a.distributeSeries&&a.stackBars?0:j,p=a.horizontalBars?{x:o.x1+i.projectValue(f&&f.x?f.x:0,j,b.normalized.series[d]),y:o.y1-l.projectValue(f&&f.y?f.y:0,u,b.normalized.series[d])}:{x:o.x1+l.projectValue(f&&f.x?f.x:0,u,b.normalized.series[d]),y:o.y1-i.projectValue(f&&f.y?f.y:0,j,b.normalized.series[d])},l instanceof pa&&(l.options.stretch||(p[l.units.pos]+=g*(a.horizontalBars?-1:1)),p[l.units.pos]+=a.stackBars||a.distributeSeries?0:k*a.seriesBarDistance*(a.horizontalBars?-1:1)),t=r[j]||q,r[j]=t-(q-p[l.counterUnits.pos]),void 0!==f){var x={};x[l.units.pos+"1"]=p[l.units.pos],x[l.units.pos+"2"]=p[l.units.pos],!a.stackBars||"accumulate"!==a.stackMode&&a.stackMode?(x[l.counterUnits.pos+"1"]=q,x[l.counterUnits.pos+"2"]=p[l.counterUnits.pos]):(x[l.counterUnits.pos+"1"]=t,x[l.counterUnits.pos+"2"]=r[j]),x.x1=Math.min(Math.max(x.x1,o.x1),o.x2),x.x2=Math.min(Math.max(x.x2,o.x1),o.x2),x.y1=Math.min(Math.max(x.y1,o.y2),o.y1),x.y2=Math.min(Math.max(x.y2,o.y2),o.y1);var y=z(c,j);s=h.elem("line",x,a.classNames.bar).attr({"ct:value":[f.x,f.y].filter(e).join(","),"ct:meta":w(y)}),this.eventEmitter.emit("draw",v({type:"bar",value:f,index:j,meta:y,series:c,seriesIndex:d,axisX:m,axisY:n,chartRect:o,group:h,element:s},x))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:i.bounds,chartRect:o,axisX:m,axisY:n,svg:this.svg,options:a})}}]),b}(ha),ya={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:k,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1},za=function(a){function b(a,c,d,e){return ba(this,b),ia(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,a,c,ya,v({},ya,d),e))}return ja(b,a),ca(b,[{key:"createChart",value:function(a){var b,c,d,e,g,h=y(this.data),k=[],l=a.startAngle;this.svg=K(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),c=M(this.svg,a,ya.padding),d=Math.min(c.width()/2,c.height()/2),g=a.total||h.normalized.series.reduce(function(a,b){return a+b},0);var m=i(a.donutWidth);"%"===m.unit&&(m.value*=d/100),d-=a.donut?m.value/2:0,e="outside"===a.labelPosition||a.donut?d:"center"===a.labelPosition?0:d/2,e+=a.labelOffset;var n={x:c.x1+c.width()/2,y:c.y2+c.height()/2},o=1===h.raw.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;h.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)),h.raw.series.forEach(function(c,i){if(0!==h.normalized.series[i]||!a.ignoreEmptyValues){k[i].attr({"ct:series-name":c.name}),k[i].addClass([a.classNames.series,c.className||a.classNames.series+"-"+j(i)].join(" "));var p=g>0?l+h.normalized.series[i]/g*360:0,q=Math.max(0,l-(0===i||o?0:.2));p-q>=359.99&&(p=q+359.99);var r=u(n.x,n.y,d,q),s=u(n.x,n.y,d,p),t=new sa(!a.donut).move(s.x,s.y).arc(d,d,0,p-l>180,0,r.x,r.y);a.donut||t.line(n.x,n.y);var v=k[i].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(v.attr({"ct:value":h.normalized.series[i],"ct:meta":w(c.meta)}),a.donut&&v.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:h.normalized.series[i],totalDataSum:g,index:i,meta:c.meta,series:c,group:k[i],element:v,path:t.clone(),center:n,radius:d,startAngle:l,endAngle:p}),a.showLabel){var x;x=1===h.raw.series.length?{x:n.x,y:n.y}:u(n.x,n.y,e,l+(p-l)/2);var y;y=h.normalized.labels&&!f(h.normalized.labels[i])?h.normalized.labels[i]:h.normalized.series[i];var z=a.labelInterpolationFnc(y,i);if(z||0===z){var A=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":Y(n,x,a.labelDirection)},a.classNames.label).text(""+z);this.eventEmitter.emit("draw",{type:"label",index:i,group:b,element:A,text:""+z,x:x.x,y:x.y})}}l=p}}.bind(this)),this.eventEmitter.emit("created",{chartRect:c,svg:this.svg,options:a})}}]),b}(ha);a.Interpolation=ta,a.EventEmitter=ga,a.extend=v,a.optionsProvider=Q,a.namespaces=$,a.precision=_,a.escapingMap=aa,a.version=Z,a.replaceAll=b,a.querySelector=c,a.safeHasProperty=d,a.isNumeric=e,a.isFalseyButZero=f,a.getNumberOrUndefined=g,a.ensureUnit=h,a.quantity=i,a.alphaNumerate=j,a.noop=k,a.times=l,a.sum=m,a.mapMultiply=n,a.mapAdd=o,a.serialMap=p,a.orderOfMagnitude=q,a.projectLength=r,a.roundWithPrecision=s,a.rho=t,a.polarToCartesian=u,a.serialize=w,a.deserialize=x,a.normalizeData=y,a.getMetaData=z,a.isDataHoleValue=A,a.reverseData=B,a.getDataArray=C,a.isMultiValue=D,a.getMultiValue=E,a.getSeriesOption=F,a.splitIntoSegments=G,a.getHighLow=H,a.getBounds=I,a.createSvg=K,a.normalizePadding=L,a.createChartRect=M,a.createGrid=N,a.createGridBackground=O,a.createLabel=P,a.BaseChart=ha,a.LineChart=va,a.BarChart=xa,a.PieChart=za,a.Axis=la,a.axisUnits=ka,a.AutoScaleAxis=na,a.FixedScaleAxis=oa,a.StepAxis=pa,a.Svg=ea,a.isSupported=J,a.easings=fa,a.SvgList=da,a.SvgPath=sa,Object.defineProperty(a,"__esModule",{value:!0})}); +//# sourceMappingURL=chartist.umd.js.map \ No newline at end of file diff --git a/dist/chartist.umd.js.map b/dist/chartist.umd.js.map new file mode 100644 index 00000000..a26d78b8 --- /dev/null +++ b/dist/chartist.umd.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/core/lang.js","../src/core/functional.js","../src/core/math.js","../src/core/extend.js","../src/core/data.js","../src/svg/svg.js","../src/core/creation.js","../src/core/options-provider.js","../src/svg/svg-path.js","../src/interpolation/none.js","../src/interpolation/simple.js","../src/interpolation/step.js","../src/interpolation/cardinal.js","../src/interpolation/monotone-cubic.js","../src/charts/pie.js","../package.json!file:/home/gion/Code/chartist/tooling/system-loaders/package.json","../src/core/globals.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/classCallCheck.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/createClass.js","../src/svg/svg-list.js","../src/event/event-emitter.js","../src/charts/base.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/possibleConstructorReturn.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/inherits.js","../src/axes/axis.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/get.js","../src/axes/auto-scale-axis.js","../src/axes/fixed-scale-axis.js","../src/axes/step-axis.js","../src/charts/line.js","../src/charts/bar.js"],"names":["replaceAll","str","subStr","newSubStr","replace","RegExp","querySelector","query","Node","document","safeHasProperty","object","property","hasOwnProperty","isNumeric","value","isFinite","isFalseyButZero","getNumberOrUndefined","undefined","ensureUnit","unit","quantity","input","match","exec","alphaNumerate","n","String","fromCharCode","noop","times","length","Array","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","forEach","index","args","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","roundWithPrecision","digits","precision","pow","round","rho","gcd","p","q","f","x","divisor","x1","x2","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","extend","target","i","source","sourceProp","arguments","prop","serialize","data","JSON","stringify","Object","keys","escapingMap","reduce","key","deserialize","parse","normalizeData","reverse","multi","labelCount","output","normalized","series","getDataArray","every","labels","slice","prototype","push","getMetaData","meta","isDataHoleValue","isNaN","reverseData","recursiveConvert","multiValue","y","isMultiValue","getMultiValue","dimension","getSeriesOption","options","name","seriesOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","segments","hole","fillHoles","increasingX","getHighLow","recursiveHighLow","findHigh","highLow","high","findLow","low","toUpperCase","Number","MAX_VALUE","referenceValue","min","getBounds","scaleMinSpace","onlyInteger","safeIncrement","increment","EPSILON","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","isSupported","feature","implementation","hasFeature","createSvg","container","width","height","className","svg","call","querySelectorAll","filter","getAttributeNS","namespaces","xmlns","removeChild","Svg","attr","addClass","appendChild","_node","normalizePadding","padding","fallback","top","right","bottom","left","createChartRect","fallbackPadding","hasAxis","axisX","axisY","yAxisOffset","offset","xAxisOffset","normalizedPadding","chartPadding","chartRect","this","y1","y2","position","createGrid","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","optionsProvider","responsiveOptions","updateCurrentOptions","mediaEvent","previousOptions","currentOptions","baseOptions","mql","window","matchMedia","matches","removeMediaQueryListeners","removeListener","mediaQueryListeners","addListener","element","command","params","pathElements","relative","pathElement","toLowerCase","splice","forEachParam","pathElementIndex","paramName","paramIndex","none","path","SvgPath","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","postpone","cardinal","t","tension","c","paths","segment","z","iLen","monotoneCubic","xs","ys","ms","ds","dys","dxs","determineAnchorPosition","center","label","direction","toTheRight","version","_classCallCheck","instance","Constructor","TypeError","_createClass","defineProperties","props","descriptor","enumerable","configurable","writable","defineProperty","protoProps","staticProps","SvgList","nodeList","list","svgElements","prototypeProperty","indexOf","attributes","parent","insertFirst","Element","createElementNS","ct","firstChild","insertBefore","ns","getAttribute","namespacedAttribute","split","setAttributeNS","setAttribute","bind","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","createElement","innerHTML","fnObj","createTextNode","newElement","replaceChild","trim","names","concat","self","removedClasses","getBoundingClientRect","animations","guided","attribute","createAnimate","animationDefinition","animate","timeout","animationEasing","attributeProperties","easing","easings","begin","dur","calcMode","keySplines","keyTimes","fill","from","beginElement","err","to","remove","addEventListener","EventEmitter","handlers","event","handler","starHandler","BaseChart","supportsForeignObject","supportsAnimations","resizeListener","update","__chartist__","detach","initializeTimeoutId","setTimeout","initialize","override","createChart","getCurrentOptions","clearTimeout","removeEventListener","addEventHandler","removeEventHandler","plugins","plugin","_possibleConstructorReturn","ReferenceError","_inherits","subClass","superClass","create","setPrototypeOf","__proto__","axisUnits","Axis","ticks","rectEnd","rectStart","gridOffset","rectOffset","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","_get","get","receiver","Function","desc","getOwnPropertyDescriptor","getPrototypeOf","getter","AutoScaleAxis","_Axis","axisUnit","_this","FixedScaleAxis","sort","a","b","stepLength","StepAxis","calc","stretch","elementDescriptions","close","joinedPath","j","count","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","transformFnc","transformed","LineChart","_BaseChart","chart","seriesGroup","type","fullWidth","createGridAndLabels","showGridBackground","raw","seriesIndex","seriesElement","pathData","valueIndex","smoothing","lineSmooth","showPoint","point","showLine","clone","showArea","areaBase","areaBaseProjected","splitByCommand","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","BarChart","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","stackMode","metaData","PieChart","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","start","end","arc","sliceDonut","slicePie","rawValue","interpolatedValue","labelDirection"],"mappings":"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","file":"chartist.umd.js","sourcesContent":["/**\n * Replaces all occurrences of subStr in str with newSubStr and returns a new string.\n *\n * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @return {String}\n */\nexport function replaceAll(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\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 */\nexport function querySelector(query) {\n return query instanceof Node ? query : document.querySelector(query);\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 */\nexport function safeHasProperty(object, property) {\n return object !== null &&\n typeof object === 'object' &&\n object.hasOwnProperty(property);\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 */\nexport function isNumeric(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 */\nexport function isFalseyButZero(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 */\nexport function getNumberOrUndefined(value) {\n return isNumeric(value) ? +value : undefined;\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 */\nexport function ensureUnit(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 */\nexport function quantity(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 * 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 */\nexport function alphaNumerate(n) {\n // Limit to a-z\n return String.fromCharCode(97 + n % 26);\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 */\nexport function noop(n) {\n return n;\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 */\nexport function times(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 */\nexport function sum(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 */\nexport function mapMultiply(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 */\nexport function mapAdd(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 */\nexport function serialMap(arr, cb) {\n var result = [],\n length = Math.max.apply(null, arr.map(function(e) {\n return e.length;\n }));\n\n 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","import {precision} from './globals';\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 */\nexport function orderOfMagnitude(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 */\nexport function projectLength(axisLength, length, bounds) {\n return length / bounds.range * axisLength;\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 */\nexport function roundWithPrecision(value, digits) {\n var precision = Math.pow(10, digits || precision);\n return Math.round(value * precision) / precision;\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 */\nexport function rho(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 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 */\nexport function polarToCartesian(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 * 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 */\nexport function extend(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] = extend(target[prop], sourceProp);\n } else {\n target[prop] = sourceProp;\n }\n }\n }\n\n return target;\n}\n","import {escapingMap} from './globals';\nimport {replaceAll, safeHasProperty, getNumberOrUndefined} from './lang';\nimport {times} from './functional';\nimport {extend} from './extend';\nimport {orderOfMagnitude, projectLength, roundWithPrecision, rho} from './math';\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 */\nexport function serialize(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(escapingMap).reduce(function(result, key) {\n return replaceAll(result, key, 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 */\nexport function deserialize(data) {\n if(typeof data !== 'string') {\n return data;\n }\n\n data = Object.keys(escapingMap).reduce(function(result, key) {\n return replaceAll(result, 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 * 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 */\nexport function normalizeData(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 = 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 times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() {\n return '';\n })\n );\n\n if(reverse) {\n reverseData(output.normalized);\n }\n\n return output;\n}\n\n/**\n * Get meta data of a specific value in a series.\n *\n * @param series\n * @param index\n * @returns {*}\n */\nexport function getMetaData(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? value.meta : undefined;\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 */\nexport function isDataHoleValue(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 */\nexport function reverseData(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 */\nexport function getDataArray(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(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(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(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] = getNumberOrUndefined(value);\n } else {\n multiValue.y = getNumberOrUndefined(value);\n }\n\n multiValue.x = value.hasOwnProperty('x') ? getNumberOrUndefined(value.x) : multiValue.x;\n multiValue.y = value.hasOwnProperty('y') ? getNumberOrUndefined(value.y) : multiValue.y;\n\n return multiValue;\n\n } else {\n // We can return simple data\n return getNumberOrUndefined(value);\n }\n }\n }\n\n return data.series.map(recursiveConvert);\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 */\nexport function isMultiValue(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 */\nexport function getMultiValue(value, dimension) {\n if(isMultiValue(value)) {\n return getNumberOrUndefined(value[dimension || 'y']);\n } else {\n return getNumberOrUndefined(value);\n }\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 */\nexport function getSeriesOption(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 * 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} valueData 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 */\nexport function splitIntoSegments(pathCoordinates, valueData, options) {\n var defaultOptions = {\n increasingX: false,\n fillHoles: false\n };\n\n options = 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(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\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 */\nexport function getHighLow(data, options, dimension) {\n // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred\n options = 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 * 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 */\nexport function getBounds(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 = 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 = projectLength(axisLength, bounds.step, bounds);\n var scaleUp = length < scaleMinSpace;\n var smallestFactor = onlyInteger ? 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 && projectLength(axisLength, 1, bounds) >= scaleMinSpace) {\n bounds.step = 1;\n } else if(onlyInteger && smallestFactor < bounds.step && 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 && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && 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 value *= (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 newMin = safeIncrement(newMin, bounds.step);\n }\n while (newMax - bounds.step >= bounds.high) {\n newMax = 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 = roundWithPrecision(i);\n if (value !== values[values.length - 1]) {\n values.push(i);\n }\n }\n bounds.values = values;\n return bounds;\n}\n","import {namespaces, ensureUnit, quantity, extend} from '../core/core';\nimport {SvgList} from './svg-list';\n\n/**\n * 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 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 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 */\nexport class Svg {\n\n constructor(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(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': 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 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 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(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 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 {Svg} Returns a Svg wrapper object that can be used to modify the containing SVG data\n */\n elem(name, attributes, className, insertFirst) {\n return new Svg(name, attributes, className, this, insertFirst);\n }\n\n /**\n * Returns the parent Chartist.SVG wrapper object\n *\n * @memberof Svg\n * @return {Svg} Returns a 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 parent() {\n return this._node.parentNode instanceof SVGElement ? new Svg(this._node.parentNode) : null;\n }\n\n /**\n * This method returns a Svg wrapper around the root SVG element of the current tree.\n *\n * @memberof Svg\n * @return {Svg} The root SVG element wrapped in a Svg element\n */\n root() {\n var node = this._node;\n while(node.nodeName !== 'svg') {\n node = node.parentNode;\n }\n return new 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 Svg wrapper.\n *\n * @memberof Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {Svg} The SVG wrapper for the element found or null if no element was found\n */\n querySelector(selector) {\n var foundNode = this._node.querySelector(selector);\n return foundNode ? new 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 Svg.List wrapper.\n *\n * @memberof Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {SvgList} The SVG wrapper list for the element found or null if no element was found\n */\n querySelectorAll(selector) {\n var foundNodes = this._node.querySelectorAll(selector);\n return foundNodes.length ? new SvgList(foundNodes) : null;\n }\n\n /**\n * Returns the underlying SVG node for the current element.\n *\n * @memberof Svg\n * @returns {Node}\n */\n 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 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 {Svg} New wrapper object that wraps the foreignObject element\n */\n 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', 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 Svg wrapper.\n *\n * @memberof Svg\n * @param {String} t The text that should be added to the text element that is created\n * @return {Svg} The same wrapper object that was used to add the newly created element\n */\n 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 Svg\n * @return {Svg} The same wrapper object that got emptied\n */\n 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 Svg\n * @return {Svg} The parent wrapper object of the element that got removed\n */\n 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 Svg\n * @param {Svg} newElement The new Svg object that will be used to replace the current wrapper object\n * @return {Svg} The wrapper of the new element\n */\n 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 Svg\n * @param {Svg} element The 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 {Svg} The wrapper of the appended object\n */\n 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 Svg\n * @return {Array} A list of classes or an empty array if there are no classes on the current element\n */\n 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 Svg\n * @param {String} names A white space separated list of class names\n * @return {Svg} The wrapper of the current element\n */\n addClass(names) {\n this._node.setAttribute('class',\n this.classes()\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 Svg\n * @param {String} names A white space separated list of class names\n * @return {Svg} The wrapper of the current element\n */\n removeClass(names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n this._node.setAttribute('class', this.classes().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 Svg\n * @return {Svg} The wrapper of the current element\n */\n removeAllClasses() {\n this._node.setAttribute('class', '');\n return this;\n }\n\n /**\n * Get element height using `getBoundingClientRect`\n *\n * @memberof Svg\n * @return {Number} The elements height in pixels\n */\n 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 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 `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 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 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 {Svg} The current element where the animation was added\n */\n 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 animationEasing;\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 animationEasing = animationDefinition.easing instanceof Array ?\n animationDefinition.easing :\n easings[animationDefinition.easing];\n delete animationDefinition.easing;\n }\n\n // If numeric dur or begin was provided we assume milli seconds\n animationDefinition.begin = ensureUnit(animationDefinition.begin, 'ms');\n animationDefinition.dur = ensureUnit(animationDefinition.dur, 'ms');\n\n if(animationEasing) {\n animationDefinition.calcMode = 'spline';\n animationDefinition.keySplines = animationEasing.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 = quantity(animationDefinition.begin || 0).value;\n animationDefinition.begin = 'indefinite';\n }\n\n animate = this.elem('animate', 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\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 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 */\nexport function isSupported(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 `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 Svg\n */\nexport const easings = {\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","import {namespaces} from './globals';\nimport {Svg} from '../svg/svg';\nimport {quantity} from './lang';\nimport {extend} from './extend';\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 */\nexport function createSvg(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(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 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 * 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 */\nexport function normalizePadding(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/**\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 */\nexport function createChartRect(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() || quantity(options.width).value || 0;\n var height = svg.height() || quantity(options.height).value || 0;\n var normalizedPadding = 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 */\nexport function createGrid(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 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 */\nexport function createGridBackground(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 */\nexport function createLabel(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, 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', extend({\n type: 'label',\n axis: axis,\n index: index,\n group: group,\n element: labelElement,\n text: labels[index]\n }, positionalData));\n}\n","import {extend} from './extend';\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 */\nexport function optionsProvider(options, responsiveOptions, eventEmitter) {\n var baseOptions = extend({}, options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions(mediaEvent) {\n var previousOptions = currentOptions;\n currentOptions = 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 = 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 extend({}, currentOptions);\n }\n };\n}\n","import {extend} from '../core/core';\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 SvgPath\n * @type {Object}\n */\nconst 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 SvgPath\n * @type {Object}\n */\nconst 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\nfunction element(command, params, pathElements, pos, relative, data) {\n var pathElement = extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params, data ? { data: data } : {} );\n\n pathElements.splice(pos, 0, pathElement);\n}\n\nfunction 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 SvgPath\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 */\nexport class SvgPath {\n /**\n * This static function on `SvgPath` is joining multiple paths together into one paths.\n *\n * @memberof SvgPath\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 {SvgPath}\n */\n static join(paths, close, options) {\n var joinedPath = new SvgPath(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 constructor(close, options) {\n this.pathElements = [];\n this.pos = 0;\n this.close = close;\n this.options = 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 SvgPath\n * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array.\n * @return {SvgPath|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 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 SvgPath\n * @param {Number} count Number of path elements that should be removed from the current position.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\n * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n 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 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 SvgPath\n * @return {String}\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\n * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath}\n */\n clone(close) {\n var c = new SvgPath(close || this.close);\n c.pos = this.pos;\n c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) {\n return extend({}, pathElement);\n });\n c.options = 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 SvgPath\n * @param {String} command The command you'd like to use to split the path\n * @return {Array}\n */\n splitByCommand(command) {\n var split = [\n new SvgPath()\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 SvgPath());\n }\n\n split[split.length - 1].pathElements.push(pathElement);\n });\n\n return split;\n }\n}\n","import {extend, getMultiValue} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function none(options) {\n var defaultOptions = {\n fillHoles: false\n };\n options = extend({}, defaultOptions, options);\n return function none(pathCoordinates, valueData) {\n var path = new SvgPath();\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(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","import {extend} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function simple(options) {\n var defaultOptions = {\n divisor: 2,\n fillHoles: false\n };\n options = extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates, valueData) {\n var path = new SvgPath();\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","import {extend} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function step(options) {\n var defaultOptions = {\n postpone: true,\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new SvgPath();\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","import {extend, splitIntoSegments} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\nimport {none} from './none';\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 */\nexport function cardinal(options) {\n var defaultOptions = {\n tension: 1,\n fillHoles: false\n };\n\n options = 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 = splitIntoSegments(pathCoordinates, valueData, {\n fillHoles: options.fillHoles\n });\n\n if(!segments.length) {\n // If there were no segments return 'none' interpolation\n return 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 SvgPath.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 none()(pathCoordinates, valueData);\n }\n\n var path = new SvgPath().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","import {extend, splitIntoSegments} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\nimport {none} from './none';\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 */\nexport function monotoneCubic(options) {\n var defaultOptions = {\n fillHoles: false\n };\n\n options = 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 = 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 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 SvgPath.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 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 SvgPath().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","import {alphaNumerate, quantity, isFalseyButZero} from '../core/lang';\nimport {noop} from '../core/functional';\nimport {polarToCartesian} from '../core/math';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize} from '../core/data';\nimport {createSvg, createChartRect} from '../core/creation';\nimport {SvgPath} from '../svg/svg-path';\nimport {BaseChart} from './base';\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 */\nconst 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: 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 */\nexport 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\nexport class PieChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates the pie chart\n *\n * @param options\n */\n createChart(options) {\n var data = 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 = createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie);\n // Calculate charting rect\n chartRect = 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 = 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 + '-' + 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 = polarToCartesian(center.x, center.y, radius, overlappigStartAngle),\n end = 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 SvgPath(!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': 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 = 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 && !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","","export {version} from 'package.json!version';\n\n/**\n * This object contains all namespaces used within Chartist.\n *\n * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}}\n */\nexport let 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 * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number.\n *\n * @type {number}\n */\nexport let precision = 8;\n\n/**\n * A map with characters to escape for strings to be safely used as attribute values.\n *\n * @type {Object}\n */\nexport let escapingMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n '\\'': '''\n};\n","export default (function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n});","export default (function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n})();","import {Svg} from './svg';\n\n/**\n * This helper class is to wrap multiple `Svg` elements into a list where you can call the `Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Svg` on multiple elements.\n * An instance of this class is also returned by `Svg.querySelectorAll`.\n *\n * @memberof 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 */\nexport class SvgList {\n constructor(nodeList) {\n var list = this;\n\n this.svgElements = [];\n for(var i = 0; i < nodeList.length; i++) {\n this.svgElements.push(new Svg(nodeList[i]));\n }\n\n // Add delegation methods for Svg\n Object.keys(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 Svg.prototype[prototypeProperty].apply(element, args);\n });\n return list;\n };\n });\n }\n}\n","export class EventEmitter {\n constructor() {\n this.handlers = [];\n }\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 addEventHandler(event, handler) {\n this.handlers[event] = this.handlers[event] || [];\n this.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 removeEventHandler(event, handler) {\n // Only do something if there are event handlers with this name existing\n if(this.handlers[event]) {\n // If handler is set we will look for a specific handler and only remove this\n if(handler) {\n this.handlers[event].splice(this.handlers[event].indexOf(handler), 1);\n if(this.handlers[event].length === 0) {\n delete this.handlers[event];\n }\n } else {\n // If no handler is specified we remove all handlers for this event\n delete this.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 emit(event, data) {\n // Only do something if there are event handlers with this name existing\n if(this.handlers[event]) {\n this.handlers[event].forEach(function(handler) {\n handler(data);\n });\n }\n\n // Emit event to star event handlers\n if(this.handlers['*']) {\n this.handlers['*'].forEach(function(starHandler) {\n starHandler(event, data);\n });\n }\n }\n}\n","import {querySelector, extend, optionsProvider} from '../core/core';\nimport {EventEmitter} from '../event/event-emitter';\nimport {isSupported} from '../svg/svg';\n\nexport class BaseChart {\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 constructor(query, data, defaultOptions, options, responsiveOptions) {\n this.container = 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 = new EventEmitter();\n this.supportsForeignObject = isSupported('Extensibility');\n this.supportsAnimations = 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(this.initialize.bind(this), 0);\n }\n\n createChart() {\n throw new Error('Base chart type can\\'t be instantiated!');\n }\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 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 = 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 = 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 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 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 off(event, handler) {\n this.eventEmitter.removeEventHandler(event, handler);\n return this;\n }\n\n 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 = 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","export default (function (self, call) {\n if (!self) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\n});","export default (function (subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass);\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n});","import {isFalseyButZero} from '../core/lang';\nimport {createGrid, createLabel} from '../core/creation';\n\nexport const 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\nexport class Axis {\n initialize(units, chartRect, ticks, options) {\n this.units = units;\n this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x;\n this.options = options;\n this.chartRect = chartRect;\n this.axisLength = chartRect[this.units.rectEnd] - chartRect[this.units.rectStart];\n this.gridOffset = chartRect[this.units.rectOffset];\n this.ticks = ticks;\n }\n\n projectValue(value, index, data) {\n throw new Error('Base axis can\\'t be instantiated!');\n }\n\n 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(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 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 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","export default (function get(object, property, receiver) {\n if (object === null) object = Function.prototype;\n var desc = Object.getOwnPropertyDescriptor(object, property);\n\n if (desc === undefined) {\n var parent = Object.getPrototypeOf(object);\n\n if (parent === null) {\n return undefined;\n } else {\n return get(parent, property, receiver);\n }\n } else if (\"value\" in desc) {\n return desc.value;\n } else {\n var getter = desc.get;\n\n if (getter === undefined) {\n return undefined;\n }\n\n return getter.call(receiver);\n }\n});","import {getBounds, getHighLow, getMultiValue} from '../core/data';\nimport {Axis} from './axis';\n\nexport class AutoScaleAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\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 || getHighLow(data, options, axisUnit.pos);\n this.bounds = 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 super.initialize(axisUnit, chartRect, this.bounds.values, options);\n }\n\n projectValue(value) {\n return this.axisLength * (+getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range;\n }\n}\n","import {getMultiValue, getHighLow} from '../core/data';\nimport {times} from '../core/functional';\nimport {Axis} from './axis';\n\nexport class FixedScaleAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\n\n var highLow = options.highLow || getHighLow(data, options, axisUnit.pos);\n this.divisor = options.divisor || 1;\n this.ticks = options.ticks || 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 super.initialize(axisUnit, chartRect, this.ticks, options);\n\n this.stepLength = this.axisLength / this.divisor;\n }\n\n projectValue(value) {\n return this.axisLength * (+getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min);\n }\n}\n","import {Axis} from './axis';\n\nexport class StepAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\n super.initialize(axisUnit, chartRect, options.ticks, options);\n\n var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0));\n this.stepLength = this.axisLength / calc;\n }\n\n projectValue(value, index) {\n return this.stepLength * index;\n }\n}\n","import {isNumeric, alphaNumerate} from '../core/lang';\nimport {noop} from '../core/functional';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize, getMetaData, getSeriesOption} from '../core/data';\nimport {createSvg, createChartRect, createGridBackground} from '../core/creation';\nimport {StepAxis, AutoScaleAxis, axisUnits} from '../axes/axes';\nimport {BaseChart} from './base';\nimport {monotoneCubic, none} from '../interpolation/interpolation';\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 */\nconst 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: 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: 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\nexport class LineChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates a new chart\n *\n */\n createChart(options) {\n var data = normalizeData(this.data, options.reverseData, true);\n\n // Create new svg object\n this.svg = 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 = createChartRect(this.svg, options, defaultOptions.padding);\n var axisX, axisY;\n\n if(options.axisX.type === undefined) {\n axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n ticks: data.normalized.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, {\n high: isNumeric(options.high) ? options.high : options.axisY.high,\n low: isNumeric(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = new options.axisY.type(axisUnits.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 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': 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 + '-' + 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: getMetaData(series, valueIndex)\n });\n }.bind(this));\n\n var seriesOptions = {\n lineSmooth: getSeriesOption(series, options, 'lineSmooth'),\n showPoint: getSeriesOption(series, options, 'showPoint'),\n showLine: getSeriesOption(series, options, 'showLine'),\n showArea: getSeriesOption(series, options, 'showArea'),\n areaBase: getSeriesOption(series, options, 'areaBase')\n };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? monotoneCubic() : 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(isNumeric).join(','),\n 'ct:meta': 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","import {isNumeric, alphaNumerate} from '../core/lang';\nimport {noop, serialMap} from '../core/functional';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize, getMetaData, getHighLow} from '../core/data';\nimport {createSvg, createChartRect, createGridBackground} from '../core/creation';\nimport {AutoScaleAxis, StepAxis, axisUnits} from '../axes/axes';\nimport {BaseChart} from './base';\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 */\nconst 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: 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: 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\nexport class BarChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates a new chart\n *\n */\n createChart(options) {\n var data;\n var highLow;\n\n if(options.distributeSeries) {\n data = 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 = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n }\n\n // Create new svg element\n this.svg = 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 = 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 = getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y');\n\n } else {\n\n highLow = 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 = 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 AutoScaleAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n\n if(options.axisY.type === undefined) {\n labelAxis = axisY = new StepAxis(axisUnits.y, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisY = new options.axisY.type(axisUnits.units.y, data.normalized.series, chartRect, 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 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': 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 + '-' + 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 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 = 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(isNumeric).join(','),\n 'ct:meta': serialize(metaData)\n });\n\n this.eventEmitter.emit('draw', 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"]} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..086a631f --- /dev/null +++ b/index.html @@ -0,0 +1,70 @@ + + + + + Chartist.js - Testbed + + + + + + + +
    + + + diff --git a/jspm.config.js b/jspm.config.js new file mode 100644 index 00000000..545d667c --- /dev/null +++ b/jspm.config.js @@ -0,0 +1,47 @@ +SystemJS.config({ + paths: { + "npm:": "jspm_packages/npm/", + "github:": "jspm_packages/github/", + "chartist/": "src/" + }, + browserConfig: { + "baseURL": "/" + }, + devConfig: { + "map": { + "plugin-babel": "npm:systemjs-plugin-babel@0.0.16" + } + }, + transpiler: "plugin-babel", + packages: { + "chartist": { + "main": "index.js", + "defaultExtension": "js", + "format": "esm", + "meta": { + "*.js": { + "loader": "plugin-babel" + } + } + } + } +}); + +SystemJS.config({ + packageConfigPaths: [ + "npm:@*/*.json", + "npm:*.json", + "github:*/*.json" + ], + map: { + "text": "github:systemjs/plugin-text@0.0.9" + }, + packages: {} +}); + +// Manually added +SystemJS.config({ + map: { + "version": "tooling/system-loaders/version-loader-plugin.js" + } +}); diff --git a/karma.watch.config.js b/karma.watch.config.js new file mode 100644 index 00000000..95bb102d --- /dev/null +++ b/karma.watch.config.js @@ -0,0 +1,27 @@ +module.exports = function(config) { + config.set({ + basePath: './', + frameworks: ['jasmine', 'jspm'], + autoWatch: true, + browsers: ['PhantomJS'], + reporters: ['nyan'], + files: [ + { pattern: 'src/**/*.+(js|html)', included: false }, + { pattern: 'tooling/**/*.js', included: false }, + { pattern: 'package.json', included: false }, + { pattern: 'jspm_packages/system-polyfills.js', included: false }, + 'dist/chartist.min.css' + ], + jspm: { + loadFiles: ['src/**/*.js'], + stripExtension: false, + config: 'jspm.config.js' + }, + proxies: { + '/jspm_packages/': '/base/jspm_packages/', + '/src/': '/base/src/', + '/tooling/': '/base/tooling/', + '/package.json': '/base/package.json' + } + }); +}; diff --git a/package.json b/package.json new file mode 100644 index 00000000..c2184528 --- /dev/null +++ b/package.json @@ -0,0 +1,88 @@ +{ + "name": "chartist", + "title": "Chartist.js", + "description": "Simple, responsive charts", + "version": "1.0.0", + "author": "Gion Kunz", + "homepage": "https://chartist-js.github.io/", + "repository": { + "type": "git", + "url": "https://github.com/chartist-js/chartist.git" + }, + "bugs": { + "url": "https://github.com/chartist-js/chartist/issues" + }, + "keywords": [ + "chartist", + "responsive charts", + "charts", + "charting" + ], + "files": [ + "dist", + "LICENSE-WTFPL", + "LICENSE-MIT", + "package.json", + "README.md" + ], + "style": "dist/chartist.min.css", + "main": "dist/chartist.umd.js", + "browser": "dist/chartist.umd.js", + "license": "MIT OR WTFPL", + "licenses": [ + { + "type": "WTFPL", + "url": "https://github.com/chartist-js/chartist/blob/master/LICENSE-WTFPL" + }, + { + "type": "MIT", + "url": "https://github.com/chartist-js/chartist/blob/master/LICENSE-MIT" + } + ], + "dependencies": { + "autoprefixer": "^6.5.1", + "chokidar": "^1.6.1", + "cssnano": "^3.7.7", + "debounce": "^1.0.0", + "fs-promise": "^0.5.0", + "interpolate": "^0.1.0", + "node-sass": "^3.10.1", + "postcss": "^5.2.5" + }, + "devDependencies": { + "browser-sync": "^2.17.5", + "jasmine-core": "^2.5.2", + "jspm": "beta", + "karma": "^1.3.0", + "karma-jasmine": "^1.0.2", + "karma-jspm": "^2.2.0", + "karma-nyan-reporter": "^0.2.4", + "karma-phantomjs-launcher": "^1.0.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "jspm": { + "name": "chartist", + "main": "chartist", + "dependencies": { + "text": "github:systemjs/plugin-text@^0.0.9" + }, + "devDependencies": { + "plugin-babel": "npm:systemjs-plugin-babel@^0.0.16" + } + }, + "scripts": { + "start": "yarn run test-watch & yarn run server & yarn run styles-watch", + "test-watch": "./node_modules/.bin/karma start karma.watch.config.js", + "styles-watch": "./tooling/node/styles-watch.js", + "server": "./node_modules/.bin/browser-sync start --config 'bs-config.js'", + "build": "yarn run build-styles && yarn run build-umd && yarn run build-esm", + "build-umd": "./node_modules/.bin/jspm build chartist dist/chartist.umd.js --format umd --global-name Chartist --minify --source-map-contents && ./tooling/node/banner.js dist/chartist.umd.js dist/chartist.umd.js", + "build-esm": "./node_modules/.bin/jspm build chartist dist/chartist.esm.js --format esm && ./tooling/node/banner.js dist/chartist.esm.js dist/chartist.esm.js", + "build-styles": "./tooling/node/styles.js src/styles/chartist.scss dist" + }, + "config": { + "banner": "/* Chartist.js {pkg.version}\n * Copyright © {year} 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" + } +} diff --git a/src/axes/auto-scale-axis.js b/src/axes/auto-scale-axis.js new file mode 100644 index 00000000..f195c723 --- /dev/null +++ b/src/axes/auto-scale-axis.js @@ -0,0 +1,21 @@ +import {getBounds, getHighLow, getMultiValue} from '../core/data'; +import {Axis} from './axis'; + +export class AutoScaleAxis extends Axis { + constructor(axisUnit, data, chartRect, options) { + super(); + // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options + var highLow = options.highLow || getHighLow(data, options, axisUnit.pos); + this.bounds = getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); + this.range = { + min: this.bounds.min, + max: this.bounds.max + }; + + super.initialize(axisUnit, chartRect, this.bounds.values, options); + } + + projectValue(value) { + return this.axisLength * (+getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; + } +} diff --git a/src/axes/axes.js b/src/axes/axes.js new file mode 100644 index 00000000..75d73cc3 --- /dev/null +++ b/src/axes/axes.js @@ -0,0 +1,4 @@ +export {Axis, axisUnits} from './axis'; +export {AutoScaleAxis} from './auto-scale-axis'; +export {FixedScaleAxis} from './fixed-scale-axis'; +export {StepAxis} from './step-axis'; diff --git a/src/axes/axis.js b/src/axes/axis.js new file mode 100644 index 00000000..09caa859 --- /dev/null +++ b/src/axes/axis.js @@ -0,0 +1,109 @@ +import {isFalseyButZero} from '../core/lang'; +import {createGrid, createLabel} from '../core/creation'; + +export const axisUnits = { + x: { + pos: 'x', + len: 'width', + dir: 'horizontal', + rectStart: 'x1', + rectEnd: 'x2', + rectOffset: 'y2' + }, + y: { + pos: 'y', + len: 'height', + dir: 'vertical', + rectStart: 'y2', + rectEnd: 'y1', + rectOffset: 'x1' + } +}; + +export class Axis { + initialize(units, chartRect, ticks, options) { + this.units = units; + this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; + this.options = options; + this.chartRect = chartRect; + this.axisLength = chartRect[this.units.rectEnd] - chartRect[this.units.rectStart]; + this.gridOffset = chartRect[this.units.rectOffset]; + this.ticks = ticks; + } + + projectValue(value, index, data) { + throw new Error('Base axis can\'t be instantiated!'); + } + + createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) { + var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; + var projectedValues = this.ticks.map(this.projectValue.bind(this)); + var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); + + projectedValues.forEach(function(projectedValue, index) { + var labelOffset = { + x: 0, + y: 0 + }; + + // TODO: Find better solution for solving this problem + // Calculate how much space we have available for the label + var labelLength; + if(projectedValues[index + 1]) { + // If we still have one label ahead, we can calculate the distance to the next tick / label + labelLength = projectedValues[index + 1] - projectedValue; + } else { + // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to + // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will + // still be visible inside of the chart padding. + labelLength = Math.max(this.axisLength - projectedValue, 30); + } + + // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + if(isFalseyButZero(labelValues[index]) && labelValues[index] !== '') { + return; + } + + // Transform to global coordinates using the chartRect + // We also need to set the label offset for the createLabel function + if(this.units.pos === 'x') { + projectedValue = this.chartRect.x1 + projectedValue; + labelOffset.x = chartOptions.axisX.labelOffset.x; + + // If the labels should be positioned in start position (top side for vertical axis) we need to set a + // different offset as for positioned with end (bottom) + if(chartOptions.axisX.position === 'start') { + labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } else { + labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + } + } else { + projectedValue = this.chartRect.y1 - projectedValue; + labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0); + + // If the labels should be positioned in start position (left side for horizontal axis) we need to set a + // different offset as for positioned with end (right side) + if(chartOptions.axisY.position === 'start') { + labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10; + } else { + labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; + } + } + + if(axisOptions.showGrid) { + createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [ + chartOptions.classNames.grid, + chartOptions.classNames[this.units.dir] + ], eventEmitter); + } + + if(axisOptions.showLabel) { + createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [ + chartOptions.classNames.label, + chartOptions.classNames[this.units.dir], + (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']) + ], useForeignObject, eventEmitter); + } + }.bind(this)); + } +} diff --git a/src/axes/axis.spec.js b/src/axes/axis.spec.js new file mode 100644 index 00000000..be55efcc --- /dev/null +++ b/src/axes/axis.spec.js @@ -0,0 +1,103 @@ +import {Svg} from '../svg/svg'; +import {EventEmitter} from '../event/event-emitter'; +import {Axis, axisUnits} from './axis'; + +describe('Axis', function() { + var ticks, chartRect, chartOptions, eventEmitter, gridGroup, labelGroup; + + beforeEach(function() { + eventEmitter = new EventEmitter(); + gridGroup = new Svg('g'); + labelGroup = new Svg('g'); + ticks = [1, 2]; + chartRect = { + padding: { + bottom: 5, + left: 10, + right: 15, + top: 15 + }, + y2: 15, + y1: 250, + x1: 50, + x2: 450, + width: function() { + return this.x2 - this.x1; + }, + height: function() { + return this.y1 - this.y2; + } + }; + + chartOptions = { + axisX: { + offset: 30, + position: 'end', + labelOffset: { + x: 0, + y: 0 + }, + showLabel: true, + showGrid: true + }, + classNames: { + label: 'ct-label', + labelGroup: 'ct-labels', + grid: 'ct-grid', + gridGroup: 'ct-grids', + vertical: 'ct-vertical', + horizontal: 'ct-horizontal', + start: 'ct-start', + end: 'ct-end' + } + }; + }); + + it('should skip all grid lines and labels for interpolated value of null', function() { + chartOptions.axisX.labelInterpolationFnc = function(value, index) { + return index === 0 ? null : value; + }; + + var axis = new Axis(); + axis.initialize(axisUnits.x, chartRect, ticks, null); + axis.projectValue = function(value) { + return value; + }; + + axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); + expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(1); + expect(labelGroup.querySelectorAll('.ct-label').svgElements.length).toBe(1); + }); + + it('should skip all grid lines and labels for interpolated value of undefined', function() { + chartOptions.axisX.labelInterpolationFnc = function(value, index) { + return index === 0 ? undefined : value; + }; + + var axis = new Axis(); + axis.initialize(axisUnits.x, chartRect, ticks, null); + axis.projectValue = function(value) { + return value; + }; + + axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); + expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(1); + expect(labelGroup.querySelectorAll('.ct-label').svgElements.length).toBe(1); + }); + + it('should include all grid lines and labels for interpolated value of empty strings', function() { + chartOptions.axisX.labelInterpolationFnc = function(value, index) { + return index === 0 ? '' : value; + }; + + var axis = new Axis(); + axis.initialize(axisUnits.x, chartRect, ticks, null); + axis.projectValue = function(value) { + return value; + }; + + axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); + expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(2); + expect(labelGroup.querySelectorAll('.ct-label').svgElements.length).toBe(2); + }); +}); diff --git a/src/axes/fixed-scale-axis.js b/src/axes/fixed-scale-axis.js new file mode 100644 index 00000000..117c94fb --- /dev/null +++ b/src/axes/fixed-scale-axis.js @@ -0,0 +1,30 @@ +import {getMultiValue, getHighLow} from '../core/data'; +import {times} from '../core/functional'; +import {Axis} from './axis'; + +export class FixedScaleAxis extends Axis { + constructor(axisUnit, data, chartRect, options) { + super(); + + var highLow = options.highLow || getHighLow(data, options, axisUnit.pos); + this.divisor = options.divisor || 1; + this.ticks = options.ticks || times(this.divisor).map(function(value, index) { + return highLow.low + (highLow.high - highLow.low) / this.divisor * index; + }.bind(this)); + this.ticks.sort(function(a, b) { + return a - b; + }); + this.range = { + min: highLow.low, + max: highLow.high + }; + + super.initialize(axisUnit, chartRect, this.ticks, options); + + this.stepLength = this.axisLength / this.divisor; + } + + projectValue(value) { + return this.axisLength * (+getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); + } +} diff --git a/src/axes/fixed-scale-axis.spec.js b/src/axes/fixed-scale-axis.spec.js new file mode 100644 index 00000000..027cf42d --- /dev/null +++ b/src/axes/fixed-scale-axis.spec.js @@ -0,0 +1,35 @@ +import {FixedScaleAxis} from './fixed-scale-axis'; + +describe('FixedScaleAxis', function () { + it('should order the tick array', function () { + var ticks = [10, 5, 0, -5, -10]; + var axisUnit = { + pos: 'y', + len: 'height', + dir: 'vertical', + rectStart: 'y2', + rectEnd: 'y1', + rectOffset: 'x1' + }; + var data = [[{x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5}]]; + var chartRect = { + 'padding': {'top': 15, 'right': 15, 'bottom': 5, 'left': 10}, + 'y2': 15, + 'y1': 141, + 'x1': 50, + 'x2': 269 + }; + var options = { + 'offset': 40, + 'position': 'start', + 'labelOffset': {'x': 0, 'y': 0}, + 'showLabel': true, + 'showGrid': true, + 'scaleMinSpace': 20, + 'onlyInteger': false, + 'ticks': ticks + }; + var fsaxis = new FixedScaleAxis(axisUnit, data, chartRect, options); + expect(fsaxis.ticks).toEqual([-10, -5, 0, 5, 10]); + }); +}); diff --git a/src/axes/step-axis.js b/src/axes/step-axis.js new file mode 100644 index 00000000..dbbd984a --- /dev/null +++ b/src/axes/step-axis.js @@ -0,0 +1,15 @@ +import {Axis} from './axis'; + +export class StepAxis extends Axis { + constructor(axisUnit, data, chartRect, options) { + super(); + super.initialize(axisUnit, chartRect, options.ticks, options); + + var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0)); + this.stepLength = this.axisLength / calc; + } + + projectValue(value, index) { + return this.stepLength * index; + } +} diff --git a/src/axes/step-axis.spec.js b/src/axes/step-axis.spec.js new file mode 100644 index 00000000..bf09501b --- /dev/null +++ b/src/axes/step-axis.spec.js @@ -0,0 +1,27 @@ +import {StepAxis} from './step-axis'; + +describe('StepAxis', function() { + it('should return 0 if options.ticks.length == 1', function() { + var ticks = [1], + axisUnit = { + 'pos':'y', + 'len':'height', + 'dir':'vertical', + 'rectStart':'y2', + 'rectEnd':'y1', + 'rectOffset':'x1' + }, + data = [[1]], + chartRect = { + 'y2':0, + 'y1':15, + 'x1':50, + 'x2':100 + }, + options = { + 'ticks': ticks + }, + stepAxis = new StepAxis(axisUnit, data, chartRect, options); + expect(stepAxis.stepLength).toEqual(15); + }); +}); diff --git a/src/charts/bar.js b/src/charts/bar.js new file mode 100644 index 00000000..1a88605c --- /dev/null +++ b/src/charts/bar.js @@ -0,0 +1,431 @@ +import {isNumeric, alphaNumerate} from '../core/lang'; +import {noop, serialMap} from '../core/functional'; +import {extend} from '../core/extend'; +import {normalizeData, serialize, getMetaData, getHighLow} from '../core/data'; +import {createSvg, createChartRect, createGridBackground} from '../core/creation'; +import {AutoScaleAxis, StepAxis, axisUnits} from '../axes/axes'; +import {BaseChart} from './base'; + +/** + * Default options in bar charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Bar + */ +const defaultOptions = { + // Options for X-Axis + axisX: { + // The offset of the chart drawing area to the border of the container + offset: 30, + // 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. + position: 'end', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // This value specifies the minimum width in pixel of the scale steps + scaleMinSpace: 30, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false + }, + // Options for Y-Axis + axisY: { + // The offset of the chart drawing area to the border of the container + offset: 40, + // 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. + position: 'start', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false + }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + high: undefined, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + low: undefined, + // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale. + referenceValue: 0, + // 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} + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, + // Specify the distance in pixel of bars in a group + seriesBarDistance: 15, + // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options. + stackBars: false, + // If set to 'overlap' this property will force the stacked bars to draw from the zero line. + // 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. + stackMode: 'accumulate', + // 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. + horizontalBars: false, + // 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. + distributeSeries: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // If the bar chart should add a background fill to the .ct-grids group. + showGridBackground: false, + // Override the class names that get used to generate the SVG structure of the chart + 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' + } +}; + +export class BarChart extends BaseChart { + /** + * This method creates a new bar chart and returns API object that you can use for later changes. + * + * @memberof Chartist.Bar + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // Create a simple bar chart + * var data = { + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // 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. + * new Chartist.Bar('.ct-chart', data); + * + * @example + * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 + * new Chartist.Bar('.ct-chart', { + * labels: [1, 2, 3, 4, 5, 6, 7], + * series: [ + * [1, 3, 2, -5, -3, 1, -6], + * [-5, -2, -4, -1, 2, -3, 1] + * ] + * }, { + * seriesBarDistance: 12, + * low: -10, + * high: 10 + * }); + * + */ + constructor(query, data, options, responsiveOptions) { + super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions); + } + + /** + * Creates a new chart + * + */ + createChart(options) { + var data; + var highLow; + + if(options.distributeSeries) { + data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + data.normalized.series = data.normalized.series.map(function(value) { + return [value]; + }); + } else { + data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + } + + // Create new svg element + this.svg = createSvg( + this.container, + options.width, + options.height, + options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '') + ); + + // Drawing groups in correct order + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + + if(options.stackBars && data.normalized.series.length !== 0) { + + // If stacked bars we need to calculate the high low from stacked values from each series + var serialSums = serialMap(data.normalized.series, function serialSums() { + return Array.prototype.slice.call(arguments).map(function(value) { + return value; + }).reduce(function(prev, curr) { + return { + x: prev.x + (curr && curr.x) || 0, + y: prev.y + (curr && curr.y) || 0 + }; + }, {x: 0, y: 0}); + }); + + highLow = getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y'); + + } else { + + highLow = getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y'); + } + + // Overrides of high / low from settings + highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); + highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); + + var chartRect = createChartRect(this.svg, options, defaultOptions.padding); + + var valueAxis, + labelAxisTicks, + labelAxis, + axisX, + axisY; + + // We need to set step count based on some options combinations + if(options.distributeSeries && options.stackBars) { + // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should + // use only the first label for the step axis + labelAxisTicks = data.normalized.labels.slice(0, 1); + } else { + // If distributed series are enabled but stacked bars aren't, we should use the series labels + // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array + // as the bars are normalized + labelAxisTicks = data.normalized.labels; + } + + // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. + if(options.horizontalBars) { + if(options.axisX.type === undefined) { + valueAxis = axisX = new AutoScaleAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { + highLow: highLow, + referenceValue: 0 + })); + } + + if(options.axisY.type === undefined) { + labelAxis = axisY = new StepAxis(axisUnits.y, data.normalized.series, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, options.axisY); + } + } else { + if(options.axisX.type === undefined) { + labelAxis = axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, { + ticks: labelAxisTicks + }); + } else { + labelAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX); + } + + if(options.axisY.type === undefined) { + valueAxis = axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } else { + valueAxis = axisY = new options.axisY.type(axisUnits.units.y, data.normalized.series, chartRect, extend({}, options.axisY, { + highLow: highLow, + referenceValue: 0 + })); + } + } + + // Projected 0 point + var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0)); + // Used to track the screen coordinates of stacked bars + var stackedBarValues = []; + + labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + + if (options.showGridBackground) { + createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + + // Draw the series + data.raw.series.forEach(function(series, seriesIndex) { + // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. + var biPol = seriesIndex - (data.raw.series.length - 1) / 2; + // Half of the period width between vertical grid lines used to position bars + var periodHalfLength; + // Current series SVG element + var seriesElement; + + // We need to set periodHalfLength based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array + // which is the series count and divide by 2 + periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis + // length by 2 + periodHalfLength = labelAxis.axisLength / 2; + } else { + // On regular bar charts we should just use the series length + periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2; + } + + // Adding the series group to the series element + seriesElement = seriesGroup.elem('g'); + + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesElement.attr({ + 'ct:series-name': series.name, + 'ct:meta': serialize(series.meta) + }); + + // Use series class from series data or if not set generate one + seriesElement.addClass([ + options.classNames.series, + (series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)) + ].join(' ')); + + data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { + var projected, + bar, + previousStack, + labelAxisValueIndex; + + // We need to set labelAxisValueIndex based on some options combinations + if(options.distributeSeries && !options.stackBars) { + // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection + // on the step axis for label positioning + labelAxisValueIndex = seriesIndex; + } else if(options.distributeSeries && options.stackBars) { + // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use + // 0 for projection on the label step axis + labelAxisValueIndex = 0; + } else { + // On regular bar charts we just use the value index to project on the label step axis + labelAxisValueIndex = valueIndex; + } + + // We need to transform coordinates differently based on the chart layout + if(options.horizontalBars) { + projected = { + x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]) + }; + } else { + projected = { + x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex]) + } + } + + // If the label axis is a step based axis we will offset the bar into the middle of between two steps using + // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using + // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not + // add any automated positioning. + if(labelAxis instanceof StepAxis) { + // Offset to center bar between grid lines, but only if the step axis is not stretched + if(!labelAxis.options.stretch) { + projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); + } + // Using bi-polar offset for multiple series if no stacked bars or series distribution is used + projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); + } + + // Enter value in stacked bar values used to remember previous screen value for stacking up bars + previousStack = stackedBarValues[valueIndex] || zeroPoint; + stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); + + // Skip if value is undefined + if(value === undefined) { + return; + } + + var positions = {}; + positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; + positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; + + if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) { + // Stack mode: accumulate (default) + // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line + // We want backwards compatibility, so the expected fallback without the 'stackMode' option + // to be the original behaviour (accumulate) + positions[labelAxis.counterUnits.pos + '1'] = previousStack; + positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; + } else { + // Draw from the zero line normally + // This is also the same code for Stack mode: overlap + positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; + positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; + } + + // Limit x and y so that they are within the chart rect + positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); + positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2); + positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); + positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); + + var metaData = getMetaData(series, valueIndex); + + // Create bar element + bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ + 'ct:value': [value.x, value.y].filter(isNumeric).join(','), + 'ct:meta': serialize(metaData) + }); + + this.eventEmitter.emit('draw', extend({ + type: 'bar', + value: value, + index: valueIndex, + meta: metaData, + series: series, + seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, + chartRect: chartRect, + group: seriesElement, + element: bar + }, positions)); + }.bind(this)); + }.bind(this)); + + this.eventEmitter.emit('created', { + bounds: valueAxis.bounds, + chartRect: chartRect, + axisX: axisX, + axisY: axisY, + svg: this.svg, + options: options + }); + } +} diff --git a/src/charts/base.js b/src/charts/base.js new file mode 100644 index 00000000..4b2a8e0e --- /dev/null +++ b/src/charts/base.js @@ -0,0 +1,174 @@ +import {querySelector, extend, optionsProvider} from '../core/core'; +import {EventEmitter} from '../event/event-emitter'; +import {isSupported} from '../svg/svg'; + +export class BaseChart { + /** + * Constructor of chart base class. + * + * @param query + * @param data + * @param defaultOptions + * @param options + * @param responsiveOptions + * @constructor + */ + constructor(query, data, defaultOptions, options, responsiveOptions) { + this.container = querySelector(query); + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; + this.defaultOptions = defaultOptions; + this.options = options; + this.responsiveOptions = responsiveOptions; + this.eventEmitter = new EventEmitter(); + this.supportsForeignObject = isSupported('Extensibility'); + this.supportsAnimations = isSupported('AnimationEventsAttribute'); + this.resizeListener = function resizeListener(){ + this.update(); + }.bind(this); + + if(this.container) { + // If chartist was already initialized in this container we are detaching all event listeners first + if(this.container.__chartist__) { + this.container.__chartist__.detach(); + } + + this.container.__chartist__ = this; + } + + // Using event loop for first draw to make it possible to register event listeners in the same call stack where + // the chart was created. + this.initializeTimeoutId = setTimeout(this.initialize.bind(this), 0); + } + + createChart() { + throw new Error('Base chart type can\'t be instantiated!'); + } + + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. + // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not + // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. + // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html + // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj + // The problem is with the label offsets that can't be converted into percentage and affecting the chart container + /** + * Updates the chart which currently does a full reconstruction of the SVG DOM + * + * @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. + * @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. + * @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 + * @memberof Chartist.Base + */ + update(data, options, override) { + if(data) { + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'update', + data: this.data + }); + } + + if(options) { + this.options = extend({}, override ? this.options : this.defaultOptions, options); + + // If chartist was not initialized yet, we just set the options and leave the rest to the initialization + // Otherwise we re-create the optionsProvider at this point + if(!this.initializeTimeoutId) { + this.optionsProvider.removeMediaQueryListeners(); + this.optionsProvider = optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + } + } + + // Only re-created the chart if it has been initialized yet + if(!this.initializeTimeoutId) { + this.createChart(this.optionsProvider.getCurrentOptions()); + } + + // Return a reference to the chart object to chain up calls + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + */ + detach() { + // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore + // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout + if(!this.initializeTimeoutId) { + window.removeEventListener('resize', this.resizeListener); + this.optionsProvider.removeMediaQueryListeners(); + } else { + window.clearTimeout(this.initializeTimeoutId); + } + + return this; + } + + /** + * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. + * + * @memberof Chartist.Base + * @param {String} event Name of the event. Check the examples for supported events. + * @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. + */ + on(event, handler) { + this.eventEmitter.addEventHandler(event, handler); + return this; + } + + /** + * 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. + * + * @memberof Chartist.Base + * @param {String} event Name of the event for which a handler should be removed + * @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. + */ + off(event, handler) { + this.eventEmitter.removeEventHandler(event, handler); + return this; + } + + initialize() { + // Add window resize listener that re-creates the chart + window.addEventListener('resize', this.resizeListener); + + // Obtain current options based on matching media queries (if responsive options are given) + // This will also register a listener that is re-creating the chart based on media changes + this.optionsProvider = optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); + // Register options change listener that will trigger a chart update + this.eventEmitter.addEventHandler('optionsChanged', function() { + this.update(); + }.bind(this)); + + // Before the first chart creation we need to register us with all plugins that are configured + // Initialize all relevant plugins with our chart object and the plugin options specified in the config + if(this.options.plugins) { + this.options.plugins.forEach(function(plugin) { + if(plugin instanceof Array) { + plugin[0](this, plugin[1]); + } else { + plugin(this); + } + }.bind(this)); + } + + // Event for data transformation that allows to manipulate the data before it gets rendered in the charts + this.eventEmitter.emit('data', { + type: 'initial', + data: this.data + }); + + // Create the first chart + this.createChart(this.optionsProvider.getCurrentOptions()); + + // As chart is initialized from the event loop now we can reset our timeout reference + // This is important if the chart gets initialized on the same element twice + this.initializeTimeoutId = undefined; + } +} diff --git a/src/charts/charts.js b/src/charts/charts.js new file mode 100644 index 00000000..a0a33a9d --- /dev/null +++ b/src/charts/charts.js @@ -0,0 +1,4 @@ +export {BaseChart} from './base'; +export {LineChart} from './line'; +export {BarChart} from './bar'; +export {PieChart} from './pie'; diff --git a/src/charts/line.js b/src/charts/line.js new file mode 100644 index 00000000..83ada68f --- /dev/null +++ b/src/charts/line.js @@ -0,0 +1,402 @@ +import {isNumeric, alphaNumerate} from '../core/lang'; +import {noop} from '../core/functional'; +import {extend} from '../core/extend'; +import {normalizeData, serialize, getMetaData, getSeriesOption} from '../core/data'; +import {createSvg, createChartRect, createGridBackground} from '../core/creation'; +import {StepAxis, AutoScaleAxis, axisUnits} from '../axes/axes'; +import {BaseChart} from './base'; +import {monotoneCubic, none} from '../interpolation/interpolation'; + +/** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Line + */ +const defaultOptions = { + // Options for X-Axis + axisX: { + // The offset of the labels to the chart area + offset: 30, + // 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. + position: 'end', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // 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. + type: undefined + }, + // Options for Y-Axis + axisY: { + // The offset of the labels to the chart area + offset: 40, + // 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. + position: 'start', + // Allows you to correct label positioning on this axis by positive or negative x and y offset. + labelOffset: { + x: 0, + y: 0 + }, + // If labels should be shown or not + showLabel: true, + // If the axis grid should be drawn or not + showGrid: true, + // Interpolation function that allows you to intercept the value from the axis label + labelInterpolationFnc: noop, + // 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. + type: undefined, + // This value specifies the minimum height in pixel of the scale steps + scaleMinSpace: 20, + // Use only integer values (whole numbers) for the scale steps + onlyInteger: false + }, + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // If the line should be drawn or not + showLine: true, + // If dots should be drawn or not + showPoint: true, + // If the line chart should draw an area + showArea: false, + // The base for the area chart that will be used to close the area shape (is normally 0) + areaBase: 0, + // 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. + lineSmooth: true, + // If the line chart should add a background fill to the .ct-grids group. + showGridBackground: false, + // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value + low: undefined, + // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value + high: undefined, + // 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} + chartPadding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, + // 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. + fullWidth: false, + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // Override the class names that get used to generate the SVG structure of the chart + 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' + } +}; + +export class LineChart extends BaseChart { + /** + * This method creates a new line chart. + * + * @memberof Chartist.Line + * @param {String|Node} query A selector query string or directly a DOM element + * @param {Object} data The data object that needs to consist of a labels and a series array + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object which exposes the API for the created chart + * + * @example + * // Create a simple line chart + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // As options we currently only set a static size of 300x200 px + * var options = { + * width: '300px', + * height: '200px' + * }; + * + * // 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 + * new Chartist.Line('.ct-chart', data, options); + * + * @example + * // Use specific interpolation function with configuration from the Chartist.Interpolation module + * + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [ + * [1, 1, 8, 1, 7] + * ] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 0.2 + * }) + * }); + * + * @example + * // Create a line chart with responsive options + * + * var data = { + * // A labels array that can contain any sort of values + * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + * // Our series array that contains series objects or in this case series data arrays + * series: [ + * [5, 2, 4, 2, 0] + * ] + * }; + * + * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. + * var responsiveOptions = [ + * ['screen and (min-width: 641px) and (max-width: 1024px)', { + * showPoint: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return Mon, Tue, Wed etc. on medium screens + * return value.slice(0, 3); + * } + * } + * }], + * ['screen and (max-width: 640px)', { + * showLine: false, + * axisX: { + * labelInterpolationFnc: function(value) { + * // Will return M, T, W etc. on small screens + * return value[0]; + * } + * } + * }] + * ]; + * + * new Chartist.Line('.ct-chart', data, null, responsiveOptions); + * + */ + constructor(query, data, options, responsiveOptions) { + super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions); + } + + /** + * Creates a new chart + * + */ + createChart(options) { + var data = normalizeData(this.data, options.reverseData, true); + + // Create new svg object + this.svg = createSvg(this.container, options.width, options.height, options.classNames.chart); + // Create groups for labels, grid and series + var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + var seriesGroup = this.svg.elem('g'); + var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + + var chartRect = createChartRect(this.svg, options, defaultOptions.padding); + var axisX, axisY; + + if(options.axisX.type === undefined) { + axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { + ticks: data.normalized.labels, + stretch: options.fullWidth + })); + } else { + axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX); + } + + if(options.axisY.type === undefined) { + axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { + high: isNumeric(options.high) ? options.high : options.axisY.high, + low: isNumeric(options.low) ? options.low : options.axisY.low + })); + } else { + axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, options.axisY); + } + + axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + + if (options.showGridBackground) { + createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + + // Draw the series + data.raw.series.forEach(function(series, seriesIndex) { + var seriesElement = seriesGroup.elem('g'); + + // Write attributes to series group element. If series name or meta is undefined the attributes will not be written + seriesElement.attr({ + 'ct:series-name': series.name, + 'ct:meta': serialize(series.meta) + }); + + // Use series class from series data or if not set generate one + seriesElement.addClass([ + options.classNames.series, + (series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)) + ].join(' ')); + + var pathCoordinates = [], + pathData = []; + + data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { + var p = { + x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex]) + }; + pathCoordinates.push(p.x, p.y); + pathData.push({ + value: value, + valueIndex: valueIndex, + meta: getMetaData(series, valueIndex) + }); + }.bind(this)); + + var seriesOptions = { + lineSmooth: getSeriesOption(series, options, 'lineSmooth'), + showPoint: getSeriesOption(series, options, 'showPoint'), + showLine: getSeriesOption(series, options, 'showLine'), + showArea: getSeriesOption(series, options, 'showArea'), + areaBase: getSeriesOption(series, options, 'areaBase') + }; + + var smoothing = typeof seriesOptions.lineSmooth === 'function' ? + seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? monotoneCubic() : none()); + // Interpolating path where pathData will be used to annotate each path element so we can trace back the original + // index, value and meta data + var path = smoothing(pathCoordinates, pathData); + + // If we should show points we need to create them now to avoid secondary loop + // Points are drawn from the pathElements returned by the interpolation function + // Small offset for Firefox to render squares correctly + if (seriesOptions.showPoint) { + + path.pathElements.forEach(function(pathElement) { + var point = seriesElement.elem('line', { + x1: pathElement.x, + y1: pathElement.y, + x2: pathElement.x + 0.01, + y2: pathElement.y + }, options.classNames.point).attr({ + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(isNumeric).join(','), + 'ct:meta': serialize(pathElement.data.meta) + }); + + this.eventEmitter.emit('draw', { + type: 'point', + value: pathElement.data.value, + index: pathElement.data.valueIndex, + meta: pathElement.data.meta, + series: series, + seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, + group: seriesElement, + element: point, + x: pathElement.x, + y: pathElement.y + }); + }.bind(this)); + } + + if(seriesOptions.showLine) { + var line = seriesElement.elem('path', { + d: path.stringify() + }, options.classNames.line, true); + + this.eventEmitter.emit('draw', { + type: 'line', + values: data.normalized.series[seriesIndex], + path: path.clone(), + chartRect: chartRect, + index: seriesIndex, + series: series, + seriesIndex: seriesIndex, + seriesMeta: series.meta, + axisX: axisX, + axisY: axisY, + group: seriesElement, + element: line + }); + } + + // Area currently only works with axes that support a range! + if(seriesOptions.showArea && axisY.range) { + // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); + + // We project the areaBase value into screen coordinates + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); + + // In order to form the area we'll first split the path by move commands so we can chunk it up into segments + path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { + // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area + return pathSegment.pathElements.length > 1; + }).map(function convertToArea(solidPathSegments) { + // Receiving the filtered solid path segments we can now convert those segments into fill areas + var firstElement = solidPathSegments.pathElements[0]; + var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; + + // Cloning the solid path segment with closing option and removing the first move command from the clone + // We then insert a new move that should start at the area base and draw a straight line up or down + // at the end of the path we add an additional straight line to the projected area base value + // As the closing option is set our path will be automatically closed + return solidPathSegments.clone(true) + .position(0) + .remove(1) + .move(firstElement.x, areaBaseProjected) + .line(firstElement.x, firstElement.y) + .position(solidPathSegments.pathElements.length + 1) + .line(lastElement.x, areaBaseProjected); + + }).forEach(function createArea(areaPath) { + // For each of our newly created area paths, we'll now create path elements by stringifying our path objects + // and adding the created DOM elements to the correct series group + var area = seriesElement.elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true); + + // Emit an event for each area that was drawn + this.eventEmitter.emit('draw', { + type: 'area', + values: data.normalized.series[seriesIndex], + path: areaPath.clone(), + series: series, + seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, + chartRect: chartRect, + index: seriesIndex, + group: seriesElement, + element: area + }); + }.bind(this)); + } + }.bind(this)); + + this.eventEmitter.emit('created', { + bounds: axisY.bounds, + chartRect: chartRect, + axisX: axisX, + axisY: axisY, + svg: this.svg, + options: options + }); + } +} diff --git a/src/charts/pie.js b/src/charts/pie.js new file mode 100644 index 00000000..b8a7e0bb --- /dev/null +++ b/src/charts/pie.js @@ -0,0 +1,359 @@ +import {alphaNumerate, quantity, isFalseyButZero} from '../core/lang'; +import {noop} from '../core/functional'; +import {polarToCartesian} from '../core/math'; +import {extend} from '../core/extend'; +import {normalizeData, serialize} from '../core/data'; +import {createSvg, createChartRect} from '../core/creation'; +import {SvgPath} from '../svg/svg-path'; +import {BaseChart} from './base'; + +/** + * Default options in line charts. Expand the code view to see a detailed list of options with comments. + * + * @memberof Chartist.Pie + */ +const defaultOptions = { + // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') + width: undefined, + // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') + height: undefined, + // 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} + chartPadding: 5, + // Override the class names that are used to generate the SVG structure of the chart + classNames: { + chartPie: 'ct-chart-pie', + chartDonut: 'ct-chart-donut', + series: 'ct-series', + slicePie: 'ct-slice-pie', + sliceDonut: 'ct-slice-donut', + label: 'ct-label' + }, + // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. + startAngle: 0, + // 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. + total: undefined, + // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. + donut: 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, + // If a label should be shown or not + showLabel: true, + // 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. + labelOffset: 0, + // 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. + labelPosition: 'inside', + // An interpolation function for the label value + labelInterpolationFnc: noop, + // 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. + labelDirection: 'neutral', + // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. + reverseData: false, + // If true empty values will be ignored to avoid drawing unncessary slices and labels + ignoreEmptyValues: false +}; + +/** + * Determines SVG anchor position based on direction and center parameter + * + * @param center + * @param label + * @param direction + * @return {string} + */ +export function determineAnchorPosition(center, label, direction) { + var toTheRight = label.x > center.x; + + if (toTheRight && direction === 'explode' || + !toTheRight && direction === 'implode') { + return 'start'; + } else if (toTheRight && direction === 'implode' || + !toTheRight && direction === 'explode') { + return 'end'; + } else { + return 'middle'; + } +} + +export class PieChart extends BaseChart { + /** + * This method creates a new pie chart and returns an object that can be used to redraw the chart. + * + * @memberof Chartist.Pie + * @param {String|Node} query A selector query string or directly a DOM element + * @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. + * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. + * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] + * @return {Object} An object with a version and an update method to manually redraw the chart + * + * @example + * // Simple pie chart example with four series + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }); + * + * @example + * // Drawing a donut chart + * new Chartist.Pie('.ct-chart', { + * series: [10, 2, 4, 3] + * }, { + * donut: true + * }); + * + * @example + * // Using donut, startAngle and total to draw a gauge chart + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * donut: true, + * donutWidth: 20, + * startAngle: 270, + * total: 200 + * }); + * + * @example + * // Drawing a pie chart with padding and labels that are outside the pie + * new Chartist.Pie('.ct-chart', { + * series: [20, 10, 30, 40] + * }, { + * chartPadding: 30, + * labelOffset: 50, + * labelDirection: 'explode' + * }); + * + * @example + * // Overriding the class names for individual series as well as a name and meta data. + * // The name will be written as ct:series-name attribute and the meta data will be serialized and written + * // to a ct:meta attribute. + * new Chartist.Pie('.ct-chart', { + * series: [{ + * value: 20, + * name: 'Series 1', + * className: 'my-custom-class-one', + * meta: 'Meta One' + * }, { + * value: 10, + * name: 'Series 2', + * className: 'my-custom-class-two', + * meta: 'Meta Two' + * }, { + * value: 70, + * name: 'Series 3', + * className: 'my-custom-class-three', + * meta: 'Meta Three' + * }] + * }); + */ + constructor(query, data, options, responsiveOptions) { + super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions); + } + + /** + * Creates the pie chart + * + * @param options + */ + createChart(options) { + var data = normalizeData(this.data); + var seriesGroups = [], + labelsGroup, + chartRect, + radius, + labelRadius, + totalDataSum, + startAngle = options.startAngle; + + // Create SVG.js draw + this.svg = createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie); + // Calculate charting rect + chartRect = createChartRect(this.svg, options, defaultOptions.padding); + // Get biggest circle radius possible within chartRect + radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + // Calculate total of all series to get reference value or use total reference from optional options + totalDataSum = options.total || data.normalized.series.reduce(function (previousValue, currentValue) { + return previousValue + currentValue; + }, 0); + + var donutWidth = quantity(options.donutWidth); + if (donutWidth.unit === '%') { + donutWidth.value *= radius / 100; + } + + // 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; + + // 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) { + 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 { + // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie + // slice + labelRadius = radius / 2; + } + // Add the offset to the labelRadius where a negative offset means closed to the center of the chart + labelRadius += options.labelOffset; + + // Calculate end angle based on total sum and current data value and offset with padding + var center = { + x: chartRect.x1 + chartRect.width() / 2, + y: chartRect.y2 + chartRect.height() / 2 + }; + + // Check if there is only one non-zero value in the series array. + var hasSingleValInSeries = data.raw.series.filter(function (val) { + return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; + }).length === 1; + + // Creating the series groups + data.raw.series.forEach(function (series, index) { + seriesGroups[index] = this.svg.elem('g', null, null); + }.bind(this)); + //if we need to show labels we create the label group now + if (options.showLabel) { + labelsGroup = this.svg.elem('g', null, null); + } + + // Draw the series + // initialize series groups + data.raw.series.forEach(function (series, index) { + // If current value is zero and we are ignoring empty values then skip to next value + if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; + + // If the series is an object and contains a name or meta data we add a custom attribute + seriesGroups[index].attr({ + 'ct:series-name': series.name + }); + + // Use series class from series data or if not set generate one + seriesGroups[index].addClass([ + options.classNames.series, + (series.className || options.classNames.series + '-' + alphaNumerate(index)) + ].join(' ')); + + // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. + var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0); + + // Use slight offset so there are no transparent hairline issues + var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); + + // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle + // with Z and use 359.99 degrees + if (endAngle - overlappigStartAngle >= 359.99) { + endAngle = overlappigStartAngle + 359.99; + } + + var start = polarToCartesian(center.x, center.y, radius, overlappigStartAngle), + end = polarToCartesian(center.x, center.y, radius, endAngle); + + // 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 SvgPath(!options.donut) + .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); + } + + // Create the SVG path + // If this is a donut chart we add the donut class, otherwise just a regular slice + var pathElement = seriesGroups[index].elem('path', { + d: path.stringify() + }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie); + + // Adding the pie series value to the path + pathElement.attr({ + 'ct:value': data.normalized.series[index], + 'ct:meta': serialize(series.meta) + }); + + // If this is a donut, we add the stroke-width as style attribute + if (options.donut) { + pathElement.attr({ + 'style': 'stroke-width: ' + donutWidth.value + 'px' + }); + } + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'slice', + value: data.normalized.series[index], + totalDataSum: totalDataSum, + index: index, + meta: series.meta, + series: series, + group: seriesGroups[index], + element: pathElement, + path: path.clone(), + center: center, + radius: radius, + startAngle: startAngle, + endAngle: endAngle + }); + + // If we need to show labels we need to add the label for this slice now + if (options.showLabel) { + var labelPosition; + if (data.raw.series.length === 1) { + // If we have only 1 series, we can position the label in the center of the pie + labelPosition = { + x: center.x, + y: center.y + }; + } else { + // Position at the labelRadius distance from center and between start and end angle + labelPosition = polarToCartesian( + center.x, + center.y, + labelRadius, + startAngle + (endAngle - startAngle) / 2 + ); + } + + var rawValue; + if (data.normalized.labels && !isFalseyButZero(data.normalized.labels[index])) { + rawValue = data.normalized.labels[index]; + } else { + rawValue = data.normalized.series[index]; + } + + var interpolatedValue = options.labelInterpolationFnc(rawValue, index); + + if (interpolatedValue || interpolatedValue === 0) { + var labelElement = labelsGroup.elem('text', { + dx: labelPosition.x, + dy: labelPosition.y, + 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) + }, options.classNames.label).text('' + interpolatedValue); + + // Fire off draw event + this.eventEmitter.emit('draw', { + type: 'label', + index: index, + group: labelsGroup, + element: labelElement, + text: '' + interpolatedValue, + x: labelPosition.x, + y: labelPosition.y + }); + } + } + + // Set next startAngle to current endAngle. + // (except for last slice) + startAngle = endAngle; + }.bind(this)); + + this.eventEmitter.emit('created', { + chartRect: chartRect, + svg: this.svg, + options: options + }); + } +} diff --git a/src/core/core.js b/src/core/core.js new file mode 100644 index 00000000..01430174 --- /dev/null +++ b/src/core/core.js @@ -0,0 +1,8 @@ +export * from './globals'; +export * from './lang'; +export * from './functional'; +export * from './math'; +export * from './data'; +export * from './creation'; +export {extend} from './extend'; +export {optionsProvider} from './options-provider'; diff --git a/src/core/creation.js b/src/core/creation.js new file mode 100644 index 00000000..dfe1c86b --- /dev/null +++ b/src/core/creation.js @@ -0,0 +1,233 @@ +import {namespaces} from './globals'; +import {Svg} from '../svg/svg'; +import {quantity} from './lang'; +import {extend} from './extend'; + +/** + * Create or reinitialize the SVG element for the chart + * + * @memberof Chartist.Core + * @param {Node} container The containing DOM Node object that will be used to plant the SVG element + * @param {String} width Set the width of the SVG element. Default is 100% + * @param {String} height Set the height of the SVG element. Default is 100% + * @param {String} className Specify a class to be added to the SVG element + * @return {Object} The created/reinitialized SVG element + */ +export function createSvg(container, width, height, className) { + var svg; + + width = width || '100%'; + height = height || '100%'; + + // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it + // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ + Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { + return svg.getAttributeNS(namespaces.xmlns, 'ct'); + }).forEach(function removePreviousElement(svg) { + container.removeChild(svg); + }); + + // Create svg object with width and height or use 100% as default + svg = new Svg('svg').attr({ + width: width, + height: height + }).addClass(className).attr({ + style: 'width: ' + width + '; height: ' + height + ';' + }); + + // Add the DOM node to our container + container.appendChild(svg._node); + + return svg; +} + +/** + * Converts a number into a padding object. + * + * @memberof Chartist.Core + * @param {Object|Number} padding + * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed + * @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. + */ +export function normalizePadding(padding, fallback) { + fallback = fallback || 0; + + return typeof padding === 'number' ? { + top: padding, + right: padding, + bottom: padding, + left: padding + } : { + top: typeof padding.top === 'number' ? padding.top : fallback, + right: typeof padding.right === 'number' ? padding.right : fallback, + bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback, + left: typeof padding.left === 'number' ? padding.left : fallback + }; +} + +/** + * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right + * + * @memberof Chartist.Core + * @param {Object} svg The svg element for the chart + * @param {Object} options The Object that contains all the optional values for the chart + * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used + * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements + */ +export function createChartRect(svg, options, fallbackPadding) { + var hasAxis = !!(options.axisX || options.axisY); + var yAxisOffset = hasAxis ? options.axisY.offset : 0; + var xAxisOffset = hasAxis ? options.axisX.offset : 0; + // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 + var width = svg.width() || quantity(options.width).value || 0; + var height = svg.height() || quantity(options.height).value || 0; + var normalizedPadding = normalizePadding(options.chartPadding, fallbackPadding); + + // If settings were to small to cope with offset (legacy) and padding, we'll adjust + width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right); + height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom); + + var chartRect = { + padding: normalizedPadding, + width: function () { + return this.x2 - this.x1; + }, + height: function () { + return this.y1 - this.y2; + } + }; + + if(hasAxis) { + if (options.axisX.position === 'start') { + chartRect.y2 = normalizedPadding.top + xAxisOffset; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } else { + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1); + } + + if (options.axisY.position === 'start') { + chartRect.x1 = normalizedPadding.left + yAxisOffset; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1); + } + } else { + chartRect.x1 = normalizedPadding.left; + chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); + chartRect.y2 = normalizedPadding.top; + chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); + } + + return chartRect; +} + +/** + * Creates a grid line based on a projected value. + * + * @memberof Chartist.Core + * @param position + * @param index + * @param axis + * @param offset + * @param length + * @param group + * @param classes + * @param eventEmitter + */ +export function createGrid(position, index, axis, offset, length, group, classes, eventEmitter) { + var positionalData = {}; + positionalData[axis.units.pos + '1'] = position; + positionalData[axis.units.pos + '2'] = position; + positionalData[axis.counterUnits.pos + '1'] = offset; + positionalData[axis.counterUnits.pos + '2'] = offset + length; + + var gridElement = group.elem('line', positionalData, classes.join(' ')); + + // Event for grid draw + eventEmitter.emit('draw', + extend({ + type: 'grid', + axis: axis, + index: index, + group: group, + element: gridElement + }, positionalData) + ); +} + +/** + * Creates a grid background rect and emits the draw event. + * + * @memberof Chartist.Core + * @param gridGroup + * @param chartRect + * @param className + * @param eventEmitter + */ +export function createGridBackground(gridGroup, chartRect, className, eventEmitter) { + var gridBackground = gridGroup.elem('rect', { + x: chartRect.x1, + y: chartRect.y2, + width: chartRect.width(), + height: chartRect.height() + }, className, true); + + // Event for grid background draw + eventEmitter.emit('draw', { + type: 'gridBackground', + group: gridGroup, + element: gridBackground + }); +} + +/** + * Creates a label based on a projected value and an axis. + * + * @memberof Chartist.Core + * @param position + * @param length + * @param index + * @param labels + * @param axis + * @param axisOffset + * @param labelOffset + * @param group + * @param classes + * @param useForeignObject + * @param eventEmitter + */ +export function createLabel(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { + var labelElement; + var positionalData = {}; + + positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; + positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; + positionalData[axis.units.len] = length; + positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10); + + 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] + ''; + + labelElement = group.foreignObject(content, extend({ + style: 'overflow: visible;' + }, positionalData)); + } else { + labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]); + } + + eventEmitter.emit('draw', extend({ + type: 'label', + axis: axis, + index: index, + group: group, + element: labelElement, + text: labels[index] + }, positionalData)); +} diff --git a/src/core/creation.spec.js b/src/core/creation.spec.js new file mode 100644 index 00000000..2893b411 --- /dev/null +++ b/src/core/creation.spec.js @@ -0,0 +1,216 @@ +import {addFixture, initializeFixtures, destroyFixtures} from '../testing/fixtures'; +import {createSvg, createGrid, createGridBackground, normalizePadding} from './creation'; +import {EventEmitter} from '../event/event-emitter'; +import {Svg} from '../svg/svg'; + +describe('Creation', () => { + beforeEach(() => initializeFixtures()); + afterEach(() => destroyFixtures()); + + describe('createSvg', () => { + it('should not remove non-chartist svg elements', () => { + const fixture = addFixture(` +
    + +
    + +
    +
    + `); + + const container = fixture.wrapper.querySelector('#chart-container'); + const svg = createSvg(container, '500px', '400px', 'ct-fish-bar'); + + expect(svg).toBeDefined(); + expect(svg.classes()).toContain('ct-fish-bar'); + expect(container).toContainElement('#foo'); + expect(container).toContainElement('#bar'); + }); + + it('should remove previous chartist svg elements', () => { + const fixture = addFixture(`
    `); + + const container = fixture.wrapper.querySelector('#chart-container'); + const svg1 = createSvg(container, '500px', '400px', 'ct-fish-bar'); + const svg2 = createSvg(container, '800px', '200px', 'ct-snake-bar'); + + expect(svg1).toBeDefined(); + expect(svg1.classes()).toContain('ct-fish-bar'); + expect(svg2).toBeDefined(); + expect(svg2.classes()).toContain('ct-snake-bar'); + expect(container).not.toContainElement('.ct-fish-bar'); + expect(container).toContainElement('.ct-snake-bar'); + }); + }); + + describe('createGrid', () => { + let group, axis, classes, eventEmitter, position, length, offset; + + beforeEach(() => { + eventEmitter = new EventEmitter(); + group = new Svg('g'); + axis = { + units: { + pos : 'x' + }, + counterUnits: { + pos : 'y' + } + }; + classes = []; + position = 10; + length = 100; + offset = 20; + }); + + function onCreated(fn, done) { + eventEmitter.addEventHandler('draw', (grid) => { + fn(grid); + done(); + }); + createGrid(position, 1, axis, offset, length, group, classes, eventEmitter); + } + + it('should add single grid line to group', (done) => { + onCreated(() => expect(group.querySelectorAll('line').svgElements.length).toBe(1), done); + }); + + it('should draw line', (done) => { + onCreated(() => { + const line = group.querySelector('line'); + expect(line.attr('x1')).toBe('10'); + expect(line.attr('x2')).toBe('10'); + expect(line.attr('y1')).toBe('20'); + expect(line.attr('y2')).toBe('120'); + }, done); + }); + + it('should draw horizontal line', (done) => { + axis.units.pos = 'y'; + axis.counterUnits.pos = 'x'; + onCreated(() => { + const line = group.querySelector('line'); + expect(line.attr('y1')).toBe('10'); + expect(line.attr('y2')).toBe('10'); + expect(line.attr('x1')).toBe('20'); + expect(line.attr('x2')).toBe('120'); + }, done); + }); + }); + + describe('createGridBackground', () => { + let group, chartRect, className, eventEmitter; + + beforeEach(() => { + eventEmitter = new EventEmitter(); + group = new Svg('g'); + className = 'ct-test'; + chartRect = { + x1: 5, + y2: 10, + _width: 100, + _height: 50, + width() { + return this._width; + }, + height() { + return this._height; + } + }; + }); + + function onCreated(fn, done) { + eventEmitter.addEventHandler('draw', (data) => { + fn(data); + done(); + }); + createGridBackground(group, chartRect, className, eventEmitter); + } + + it('should add rect', (done) => { + onCreated(() => { + const rects = group.querySelectorAll('rect').svgElements; + expect(rects.length).toBe(1); + const rect = rects[0]; + expect(rect.attr('x')).toBe('5'); + expect(rect.attr('y')).toBe('10'); + expect(rect.attr('width')).toBe('100'); + expect(rect.attr('height')).toBe('50'); + expect(rect.classes()).toEqual(['ct-test']); + }, done); + }); + + it('should pass grid to event', (done) => { + onCreated((data) => { + expect(data.type).toBe('gridBackground'); + const rect = data.element; + expect(rect.attr('x')).toBe('5'); + expect(rect.attr('y')).toBe('10'); + }, done); + }); + }); + + describe('padding normalization', () => { + it('should normalize number padding', () => { + expect(normalizePadding(10)).toEqual({ + top: 10, + right: 10, + bottom: 10, + left: 10 + }); + }); + + it('should normalize number padding when 0 is passed', () => { + expect(normalizePadding(0)).toEqual({ + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + }); + + it('should normalize empty padding object with default fallback', () => { + expect(normalizePadding({})).toEqual({ + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + }); + + it('should normalize empty padding object with specified fallback', () => { + expect(normalizePadding({}, 10)).toEqual({ + top: 10, + right: 10, + bottom: 10, + left: 10 + }); + }); + + it('should normalize partial padding object with specified fallback', () => { + expect(normalizePadding({ + top: 5, + left: 5 + }, 10)).toEqual({ + top: 5, + right: 10, + bottom: 10, + left: 5 + }); + }); + + it('should not modify complete padding object', () => { + expect(normalizePadding({ + top: 5, + right: 5, + bottom: 5, + left: 5 + }, 10)).toEqual({ + top: 5, + right: 5, + bottom: 5, + left: 5 + }); + }); + }); +}); diff --git a/src/core/data.js b/src/core/data.js new file mode 100644 index 00000000..d3be0515 --- /dev/null +++ b/src/core/data.js @@ -0,0 +1,482 @@ +import {escapingMap} from './globals'; +import {replaceAll, safeHasProperty, getNumberOrUndefined} from './lang'; +import {times} from './functional'; +import {extend} from './extend'; +import {orderOfMagnitude, projectLength, roundWithPrecision, rho} from './math'; + +/** + * 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. + * If called with null or undefined the function will return immediately with null or undefined. + * + * @memberof Chartist.Core + * @param {Number|String|Object} data + * @return {String} + */ +export function serialize(data) { + if(data === null || data === undefined) { + return data; + } else if(typeof data === 'number') { + data = ''+data; + } else if(typeof data === 'object') { + data = JSON.stringify({data: data}); + } + + return Object.keys(escapingMap).reduce(function(result, key) { + return replaceAll(result, key, escapingMap[key]); + }, data); +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param {String} data + * @return {String|Number|Object} + */ +export function deserialize(data) { + if(typeof data !== 'string') { + return data; + } + + data = Object.keys(escapingMap).reduce(function(result, key) { + return replaceAll(result, escapingMap[key], key); + }, data); + + try { + data = JSON.parse(data); + data = data.data !== undefined ? data.data : data; + } catch(e) {} + + return data; +} + +/** + * Ensures that the data object passed as second argument to the charts is present and correctly initialized. + * + * @param {Object} data The data object that is passed as second argument to the charts + * @return {Object} The normalized data object + */ +export function normalizeData(data, reverse, multi) { + var labelCount; + var output = { + raw: data, + normalized: {} + }; + + // Check if we should generate some labels based on existing series data + output.normalized.series = getDataArray({ + series: data.series || [] + }, reverse, multi); + + // If all elements of the normalized data array are arrays we're dealing with + // multi series data and we need to find the largest series if they are un-even + if (output.normalized.series.every(function(value) { + return value instanceof Array; + })) { + // Getting the series with the the most elements + labelCount = Math.max.apply(null, output.normalized.series.map(function(series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = output.normalized.series.length; + } + + output.normalized.labels = (data.labels || []).slice(); + // Padding the labels to labelCount with empty strings + Array.prototype.push.apply( + output.normalized.labels, + times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() { + return ''; + }) + ); + + if(reverse) { + reverseData(output.normalized); + } + + return output; +} + +/** + * Get meta data of a specific value in a series. + * + * @param series + * @param index + * @returns {*} + */ +export function getMetaData(series, index) { + var value = series.data ? series.data[index] : series[index]; + return value ? value.meta : undefined; +} + +/** + * Checks if a value is considered a hole in the data series. + * + * @param {*} value + * @returns {boolean} True if the value is considered a data hole + */ +export function isDataHoleValue(value) { + return value === null || + value === undefined || + (typeof value === 'number' && isNaN(value)); +} + +/** + * Reverses the series, labels and series data arrays. + * + * @memberof Chartist.Core + * @param data + */ +export function reverseData(data) { + data.labels.reverse(); + data.series.reverse(); + for (var i = 0; i < data.series.length; i++) { + if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { + data.series[i].data.reverse(); + } else if(data.series[i] instanceof Array) { + data.series[i].reverse(); + } + } +} + +/** + * Convert data series into plain array + * + * @memberof Chartist.Core + * @param {Object} data The series object that contains the data to be visualized in the chart + * @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. + * @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. + * @return {Array} A plain array that contains the data to be visualized in the chart + */ +export function getDataArray(data, reverse, multi) { + // Recursively walks through nested arrays and convert string values to numbers and objects with value properties + // to values. Check the tests in data core -> data normalization for a detailed specification of expected values + function recursiveConvert(value) { + if(safeHasProperty(value, 'value')) { + // We are dealing with value object notation so we need to recurse on value property + return recursiveConvert(value.value); + } else if(safeHasProperty(value, 'data')) { + // We are dealing with series object notation so we need to recurse on data property + return recursiveConvert(value.data); + } else if(value instanceof Array) { + // Data is of type array so we need to recurse on the series + return value.map(recursiveConvert); + } else if(isDataHoleValue(value)) { + // We're dealing with a hole in the data and therefore need to return undefined + // We're also returning undefined for multi value output + return undefined; + } else { + // We need to prepare multi value output (x and y data) + if(multi) { + var multiValue = {}; + + // Single series value arrays are assumed to specify the Y-Axis value + // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] + // If multi is a string then it's assumed that it specified which dimension should be filled as default + if(typeof multi === 'string') { + multiValue[multi] = getNumberOrUndefined(value); + } else { + multiValue.y = getNumberOrUndefined(value); + } + + multiValue.x = value.hasOwnProperty('x') ? getNumberOrUndefined(value.x) : multiValue.x; + multiValue.y = value.hasOwnProperty('y') ? getNumberOrUndefined(value.y) : multiValue.y; + + return multiValue; + + } else { + // We can return simple data + return getNumberOrUndefined(value); + } + } + } + + return data.series.map(recursiveConvert); +} + +/** + * Checks if provided value object is multi value (contains x or y properties) + * + * @memberof Chartist.Core + * @param value + */ +export function isMultiValue(value) { + return typeof value === 'object' && ('x' in value || 'y' in value); +} + +/** + * 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`. + * + * @memberof Chartist.Core + * @param value + * @param dimension + * @param defaultValue + * @returns {*} + */ +export function getMultiValue(value, dimension) { + if(isMultiValue(value)) { + return getNumberOrUndefined(value[dimension || 'y']); + } else { + return getNumberOrUndefined(value); + } +} + +/** + * Helper to read series specific options from options object. It automatically falls back to the global option if + * there is no option in the series options. + * + * @param {Object} series Series object + * @param {Object} options Chartist options object + * @param {string} key The options key that should be used to obtain the options + * @returns {*} + */ +export function getSeriesOption(series, options, key) { + if(series.name && options.series && options.series[series.name]) { + var seriesOptions = options.series[series.name]; + return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key]; + } else { + return options[key]; + } +} + +/** + * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates + * valueData property describing the segment. + * + * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any + * points with undefined values are discarded. + * + * **Options** + * The following options are used to determine how segments are formed + * ```javascript + * var options = { + * // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment. + * fillHoles: false, + * // If increasingX is true, the coordinates in all segments have strictly increasing x-values. + * increasingX: false + * }; + * ``` + * + * @memberof Chartist.Core + * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn] + * @param {Array} valueData List of associated point values in the form [v1, v2 .. vn] + * @param {Object} [options] Options set by user + * @return {Array} List of segments, each containing a pathCoordinates and valueData property. + */ +export function splitIntoSegments(pathCoordinates, valueData, options) { + var defaultOptions = { + increasingX: false, + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + var segments = []; + var hole = true; + + for(var i = 0; i < pathCoordinates.length; i += 2) { + // If this value is a "hole" we set the hole flag + if(getMultiValue(valueData[i / 2].value) === undefined) { + // if(valueData[i / 2].value === undefined) { + if(!options.fillHoles) { + hole = true; + } + } else { + if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) { + // X is not increasing, so we need to make sure we start a new segment + hole = true; + } + + + // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment + if(hole) { + segments.push({ + pathCoordinates: [], + valueData: [] + }); + // As we have a valid value now, we are not in a "hole" anymore + hole = false; + } + + // Add to the segment pathCoordinates and valueData + segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); + segments[segments.length - 1].valueData.push(valueData[i / 2]); + } + } + + return segments; +} + +/** + * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. + * + * @memberof Chartist.Core + * @param {Array} data The array that contains the data to be visualized in the chart + * @param {Object} options The Object that contains the chart options + * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration + * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. + */ +export function getHighLow(data, options, dimension) { + // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred + options = extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {}); + + var highLow = { + high: options.high === undefined ? -Number.MAX_VALUE : +options.high, + low: options.low === undefined ? Number.MAX_VALUE : +options.low + }; + var findHigh = options.high === undefined; + var findLow = options.low === undefined; + + // Function to recursively walk through arrays and find highest and lowest number + function recursiveHighLow(data) { + if(data === undefined) { + return undefined; + } else if(data instanceof Array) { + for (var i = 0; i < data.length; i++) { + recursiveHighLow(data[i]); + } + } else { + var value = dimension ? +data[dimension] : +data; + + if (findHigh && value > highLow.high) { + highLow.high = value; + } + + if (findLow && value < highLow.low) { + highLow.low = value; + } + } + } + + // Start to find highest and lowest number recursively + if(findHigh || findLow) { + recursiveHighLow(data); + } + + // Overrides of high / low based on reference value, it will make sure that the invisible reference value is + // used to generate the chart. This is useful when the chart always needs to contain the position of the + // invisible reference value in the view i.e. for bipolar scales. + if (options.referenceValue || options.referenceValue === 0) { + highLow.high = Math.max(options.referenceValue, highLow.high); + highLow.low = Math.min(options.referenceValue, highLow.low); + } + + // If high and low are the same because of misconfiguration or flat data (only the same value) we need + // to set the high or low to 0 depending on the polarity + if (highLow.high <= highLow.low) { + // If both values are 0 we set high to 1 + if (highLow.low === 0) { + highLow.high = 1; + } else if (highLow.low < 0) { + // If we have the same negative value for the bounds we set bounds.high to 0 + highLow.high = 0; + } else if (highLow.high > 0) { + // If we have the same positive value for the bounds we set bounds.low to 0 + highLow.low = 0; + } else { + // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors + highLow.high = 1; + highLow.low = 0; + } + } + + return highLow; +} + +/** + * Calculate and retrieve all the bounds for the chart and return them in one array + * + * @memberof Chartist.Core + * @param {Number} axisLength The length of the Axis used for + * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. + * @param {Number} scaleMinSpace The minimum projected length a step should result in + * @param {Boolean} onlyInteger + * @return {Object} All the values to set the bounds of the chart + */ +export function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { + var i, + optimizationCounter = 0, + newMin, + newMax, + bounds = { + high: highLow.high, + low: highLow.low + }; + + bounds.valueRange = bounds.high - bounds.low; + bounds.oom = orderOfMagnitude(bounds.valueRange); + bounds.step = Math.pow(10, bounds.oom); + bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step; + bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step; + bounds.range = bounds.max - bounds.min; + bounds.numberOfSteps = Math.round(bounds.range / bounds.step); + + // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace + // If we are already below the scaleMinSpace value we will scale up + var length = projectLength(axisLength, bounds.step, bounds); + var scaleUp = length < scaleMinSpace; + var smallestFactor = onlyInteger ? rho(bounds.range) : 0; + + // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1 + if(onlyInteger && projectLength(axisLength, 1, bounds) >= scaleMinSpace) { + bounds.step = 1; + } else if(onlyInteger && smallestFactor < bounds.step && projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) { + // If step 1 was too small, we can try the smallest factor of range + // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor + // is larger than the scaleMinSpace we should go for it. + bounds.step = smallestFactor; + } else { + // Trying to divide or multiply by 2 and find the best step value + while (true) { + if (scaleUp && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { + bounds.step *= 2; + } else if (!scaleUp && projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { + bounds.step /= 2; + if(onlyInteger && bounds.step % 1 !== 0) { + bounds.step *= 2; + break; + } + } else { + break; + } + + if(optimizationCounter++ > 1000) { + throw new Error('Exceeded maximum number of iterations while optimizing scale step!'); + } + } + } + + var EPSILON = 2.221E-16; + bounds.step = Math.max(bounds.step, EPSILON); + function safeIncrement(value, increment) { + // If increment is too small use *= (1+EPSILON) as a simple nextafter + if (value === (value += increment)) { + value *= (1 + (increment > 0 ? EPSILON : -EPSILON)); + } + return value; + } + + // Narrow min and max based on new step + newMin = bounds.min; + newMax = bounds.max; + while (newMin + bounds.step <= bounds.low) { + newMin = safeIncrement(newMin, bounds.step); + } + while (newMax - bounds.step >= bounds.high) { + newMax = safeIncrement(newMax, -bounds.step); + } + bounds.min = newMin; + bounds.max = newMax; + bounds.range = bounds.max - bounds.min; + + var values = []; + for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { + var value = roundWithPrecision(i); + if (value !== values[values.length - 1]) { + values.push(i); + } + } + bounds.values = values; + return bounds; +} diff --git a/src/core/data.spec.js b/src/core/data.spec.js new file mode 100644 index 00000000..86e5eec7 --- /dev/null +++ b/src/core/data.spec.js @@ -0,0 +1,357 @@ +import {serialize, deserialize, getDataArray, getBounds, splitIntoSegments} from './data'; + +describe('Data', () => { + describe('serialization', () => { + it('should serialize and deserialize regular strings', () => { + const input = 'String test'; + expect(input).toMatch(deserialize(serialize(input))); + }); + + it('should serialize and deserialize strings with critical characters', () => { + const input = 'String test with critical characters " < > \' & &'; + expect(input).toMatch(deserialize(serialize(input))); + }); + + it('should serialize and deserialize numbers', () => { + const input = 12345.6789; + expect(input).toEqual(deserialize(serialize(input))); + }); + + it('should serialize and deserialize dates', () => { + const input = new Date(0); + expect(+input).toEqual(+new Date(deserialize(serialize(input)))); + }); + + it('should serialize and deserialize complex object types', () => { + const input = { + a: { + b: 100, + c: 'String test', + d: 'String test with critical characters " < > \' & &', + e: { + f: 'String test' + } + } + }; + + expect(input).toEqual(deserialize(serialize(input))); + }); + + it('should serialize and deserialize null, undefined and NaN', () => { + expect(null).toEqual(deserialize(serialize(null))); + expect(undefined).toEqual(deserialize(serialize(undefined))); + expect(NaN).toMatch(deserialize(serialize('NaN'))); + }); + }); + + describe('data normalization', () => { + it('should normalize mixed series types correctly', () => { + const data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + {data: [1, 0, 3, 4, 5, 6]}, + [1, {value: 0}, 3, {value: 4}, 5, 6, 7, 8], + {data: [1, 0, {value: 3}]} + ] + }; + + expect(getDataArray(data)).toEqual( + [ + [1, 0, 3, 4, 5, 6], + [1, 0, 3, 4, 5, 6, 7, 8], + [1, 0, 3] + ] + ); + }); + + it('should normalize mixed series for pie chart correctly', () => { + const data = { + series: [1, {value: 0}, 3, {value: 4}, 5, 6, 7, 8] + }; + + expect(getDataArray(data)).toEqual( + [1, 0, 3, 4, 5, 6, 7, 8] + ); + }); + + it('should normalize mixed series with string values for pie chart correctly', () => { + const data = { + series: ['1', {value: '0'}, '3', {value: '4'}, '5', '6', '7', '8'] + }; + + expect(getDataArray(data)).toEqual( + [1, 0, 3, 4, 5, 6, 7, 8] + ); + }); + + it('should normalize mixed series types with string values correctly', () => { + const data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + {data: ['1', '0', '3', '4', '5', '6']}, + ['1', {value: '0'}, '3', {value: '4'}, '5', '6', '7', '8'], + {data: ['1', '0', {value: '3'}]} + ] + }; + + expect(getDataArray(data)).toEqual( + [ + [1, 0, 3, 4, 5, 6], + [1, 0, 3, 4, 5, 6, 7, 8], + [1, 0, 3] + ] + ); + }); + + it('should normalize mixed series types with weird values correctly', () => { + const data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + {data: [null, NaN, undefined, '4', '5', '6']}, + ['1', {value: null}, '3', {value: NaN}, '5', '6', '7', '8'], + {data: ['1', '0', {value: undefined}]} + ] + }; + + expect(getDataArray(data)).toEqual( + [ + [undefined, undefined, undefined, 4, 5, 6], + [1, undefined, 3, undefined, 5, 6, 7, 8], + [1, 0, undefined] + ] + ); + }); + + it('should normalize correctly with 0 values in data series array objects', () => { + const data = { + labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + series: [{ + data: [ + {value: 1}, + {value: 4}, + {value: 2}, + {value: 7}, + {value: 2}, + {value: 0} + ] + }] + }; + + expect(getDataArray(data)).toEqual( + [[1, 4, 2, 7, 2, 0]] + ); + }); + + it('should normalize correctly with mixed dimensional input into multi dimensional output', () => { + const data = { + labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], + series: [{ + data: [ + {value: 1}, + {value: {y: 4, x: 1}}, + {y: 2, x: 2}, + NaN, + null, + {value: 7}, + {value: 2}, + {value: null}, + {y: undefined, x: NaN} + ] + }] + }; + + expect(getDataArray(data, false, true)).toEqual( + [[ + {x: undefined, y: 1}, + {x: 1, y: 4}, + {x: 2, y: 2}, + undefined, + undefined, + {x: undefined, y: 7}, + {x: undefined, y: 2}, + undefined, + {x: undefined, y: undefined} + ]] + ); + }); + + it('should normalize boolean series correctly', () => { + const data = { + series: [true, false, false, true] + }; + + expect(getDataArray(data)).toEqual( + [1, 0, 0, 1] + ); + }); + + it('should normalize date series correctly', () => { + const data = { + series: [new Date(0), new Date(1), new Date(2), new Date(3)] + }; + + expect(getDataArray(data)).toEqual( + [0, 1, 2, 3] + ); + }); + }); + + describe('getBounds', () => { + it('should return 10 steps', () => { + const bounds = getBounds(100, {high: 10, low: 1}, 10, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(10); + expect(bounds.values).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it('should return 5 steps', () => { + const bounds = getBounds(100, {high: 10, low: 1}, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(10); + expect(bounds.values).toEqual([1, 3, 5, 7, 9]); + }); + + it('should return non integer steps', () => { + const bounds = getBounds(100, {high: 2, low: 1}, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(2); + expect(bounds.values).toEqual([1, 1.25, 1.5, 1.75, 2]); + }); + + it('should return integer steps only', () => { + const bounds = getBounds(100, {high: 3, low: 1}, 20, true); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(3); + expect(bounds.values).toEqual([1, 2, 3]); + }); + + it('should return single integer step', () => { + const bounds = getBounds(100, {high: 2, low: 1}, 20, true); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(2); + expect(bounds.values).toEqual([1, 2]); + }); + + it('should floor/ceil min/max', () => { + const bounds = getBounds(100, {high: 9.9, low: 1.01}, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(10); + expect(bounds.values).toEqual([1, 3, 5, 7, 9]); + }); + + it('should floor/ceil min/max for non integers', () => { + const bounds = getBounds(100, {high: 2.9, low: 1.01}, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(3); + expect(bounds.values).toEqual([1, 1.5, 2, 2.5, 3]); + }); + + it('should floor/ceil min/max if integers only', () => { + const bounds = getBounds(100, {high: 2.9, low: 1.01}, 20, true); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(3); + expect(bounds.values).toEqual([1, 2, 3]); + }); + + it('should return neg and pos values', () => { + const bounds = getBounds(100, {high: 1.9, low: -0.9}, 20, false); + expect(bounds.min).toBe(-1); + expect(bounds.max).toBe(2); + expect(bounds.values).toEqual([-1, 0, 1, 2]); + }); + + it('should return two steps if no space', () => { + const bounds = getBounds(100, {high: 5, low: 0}, 45, false); + expect(bounds.min).toBe(0); + expect(bounds.max).toBe(5); + expect(bounds.values).toEqual([0, 4]); + }); + + it('should return single step if no space', () => { + const bounds = getBounds(100, {high: 5, low: 0}, 80, false); + expect(bounds.min).toBe(0); + expect(bounds.max).toBe(5); + expect(bounds.values).toEqual([0]); + }); + + /* + TODO: This is currently failing with the ES6 refactoring and I can't tell why + it('should return single step if range is less than epsilon', () => { + const bounds = getBounds(100, { high: 1.0000000000000002, low: 1 }, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(1.0000000000000002); + expect(bounds.low).toBe(1); + expect(bounds.high).toBe(1.0000000000000002); + expect(bounds.values).toEqual([1]); + });*/ + + it('should return single step if range is less than smallest increment', () => { + const bounds = getBounds(613.234375, {high: 1000.0000000000001, low: 999.9999999999997}, 50, false); + expect(bounds.min).toBe(999.9999999999999); + expect(bounds.max).toBe(1000); + expect(bounds.low).toBe(999.9999999999997); + expect(bounds.high).toBe(1000.0000000000001); + expect(bounds.values).toEqual([999.9999999999999]); + }); + }); + + describe('splitIntoSegments', () => { + function makeValues(arr) { + return arr.map(function (x) { + return {value: x}; + }); + } + + it('should return empty array for empty input', () => { + expect(splitIntoSegments([], [])).toEqual([]); + }); + + it('should remove undefined values', () => { + const coords = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + const values = makeValues([1, undefined, undefined, 4, undefined, 6]); + + expect(splitIntoSegments(coords, values)).toEqual([{ + pathCoordinates: [1, 2], + valueData: makeValues([1]) + }, { + pathCoordinates: [7, 8], + valueData: makeValues([4]) + }, { + pathCoordinates: [11, 12], + valueData: makeValues([6]) + }]); + }); + + it('should respect fillHoles option', () => { + const coords = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + const values = makeValues([1, undefined, undefined, 4, undefined, 6]); + const options = { + fillHoles: true + }; + + expect(splitIntoSegments(coords, values, options)).toEqual([{ + pathCoordinates: [1, 2, 7, 8, 11, 12], + valueData: makeValues([1, 4, 6]) + }]); + }); + + it('should respect increasingX option', () => { + const coords = [1, 2, 3, 4, 5, 6, 5, 6, 7, 8, 1, 2]; + const values = makeValues([1, 2, 3, 4, 5, 6]); + const options = { + increasingX: true + }; + + expect(splitIntoSegments(coords, values, options)).toEqual([{ + pathCoordinates: [1, 2, 3, 4, 5, 6], + valueData: makeValues([1, 2, 3]) + }, { + pathCoordinates: [5, 6, 7, 8], + valueData: makeValues([4, 5]) + }, { + pathCoordinates: [1, 2], + valueData: makeValues([6]) + }]); + }); + }); +}); diff --git a/src/core/extend.js b/src/core/extend.js new file mode 100644 index 00000000..610a3a31 --- /dev/null +++ b/src/core/extend.js @@ -0,0 +1,26 @@ +/** + * Simple recursive object extend + * + * @memberof Chartist.Core + * @param {Object} target Target object where the source will be merged into + * @param {Object...} sources This object (objects) will be merged into target and then target is returned + * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source + */ +export function extend(target) { + var i, source, sourceProp; + target = target || {}; + + for (i = 1; i < arguments.length; i++) { + source = arguments[i]; + for (var prop in source) { + sourceProp = source[prop]; + if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { + target[prop] = extend(target[prop], sourceProp); + } else { + target[prop] = sourceProp; + } + } + } + + return target; +} diff --git a/src/core/functional.js b/src/core/functional.js new file mode 100644 index 00000000..465b5e05 --- /dev/null +++ b/src/core/functional.js @@ -0,0 +1,84 @@ +/** + * Helps to simplify functional style code + * + * @memberof Chartist.Core + * @param {*} n This exact value will be returned by the noop function + * @return {*} The same value that was provided to the n parameter + */ +export function noop(n) { + return n; +} + +/** + * Functional style helper to produce array with given length initialized with undefined values + * + * @memberof Chartist.Core + * @param length + * @return {Array} + */ +export function times(length) { + return Array.apply(null, new Array(length)); +} + +/** + * Sum helper to be used in reduce functions + * + * @memberof Chartist.Core + * @param previous + * @param current + * @return {*} + */ +export function sum(previous, current) { + return previous + (current ? current : 0); +} + +/** + * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor. + * + * @memberof Chartist.Core + * @param {Number} factor + * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array + */ +export function mapMultiply(factor) { + return function(num) { + return num * factor; + }; +} + +/** + * Add helper to be used in `Array.map` for adding a addend to each value of an array. + * + * @memberof Chartist.Core + * @param {Number} addend + * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array + */ +export function mapAdd(addend) { + return function(num) { + return num + addend; + }; +} + +/** + * 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). + * + * @memberof Chartist.Core + * @param arr + * @param cb + * @return {Array} + */ +export function serialMap(arr, cb) { + var result = [], + length = Math.max.apply(null, arr.map(function(e) { + return e.length; + })); + + times(length).forEach(function(e, index) { + var args = arr.map(function(e) { + return e[index]; + }); + + result[index] = cb.apply(null, args); + }); + + return result; +} diff --git a/src/core/globals.js b/src/core/globals.js new file mode 100644 index 00000000..c365e880 --- /dev/null +++ b/src/core/globals.js @@ -0,0 +1,34 @@ +export {version} from 'package.json!version'; + +/** + * This object contains all namespaces used within Chartist. + * + * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}} + */ +export let 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' +}; + +/** + * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number. + * + * @type {number} + */ +export let precision = 8; + +/** + * A map with characters to escape for strings to be safely used as attribute values. + * + * @type {Object} + */ +export let escapingMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' +}; diff --git a/src/core/lang.js b/src/core/lang.js new file mode 100644 index 00000000..ccf189b7 --- /dev/null +++ b/src/core/lang.js @@ -0,0 +1,114 @@ +/** + * Replaces all occurrences of subStr in str with newSubStr and returns a new string. + * + * @param {String} str + * @param {String} subStr + * @param {String} newSubStr + * @return {String} + */ +export function replaceAll(str, subStr, newSubStr) { + return str.replace(new RegExp(subStr, 'g'), newSubStr); +} + +/** + * This is a wrapper around document.querySelector that will return the query if it's already of type Node + * + * @memberof Chartist.Core + * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly + * @return {Node} + */ +export function querySelector(query) { + return query instanceof Node ? query : document.querySelector(query); +} + +/** + * This function safely checks if an objects has an owned property. + * + * @param {Object} object The object where to check for a property + * @param {string} property The property name + * @returns {boolean} Returns true if the object owns the specified property + */ +export function safeHasProperty(object, property) { + return object !== null && + typeof object === 'object' && + object.hasOwnProperty(property); +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param value + * @returns {Boolean} + */ +export function isNumeric(value) { + return value === null ? false : isFinite(value); +} + +/** + * Returns true on all falsey values except the numeric value 0. + * + * @memberof Chartist.Core + * @param value + * @returns {boolean} + */ +export function isFalseyButZero(value) { + return !value && value !== 0; +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param value + * @returns {*} + */ +export function getNumberOrUndefined(value) { + return isNumeric(value) ? +value : undefined; +} + +/** + * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. + * + * @memberof Chartist.Core + * @param {Number} value + * @param {String} unit + * @return {String} Returns the passed number value with unit. + */ +export function ensureUnit(value, unit) { + if(typeof value === 'number') { + value = value + unit; + } + + return value; +} + +/** + * Converts a number or string to a quantity object. + * + * @memberof Chartist.Core + * @param {String|Number} input + * @return {Object} Returns an object containing the value as number and the unit as string. + */ +export function quantity(input) { + if (typeof input === 'string') { + var match = (/^(\d+)\s*(.*)$/g).exec(input); + return { + value : +match[1], + unit: match[2] || undefined + }; + } + return { value: input }; +} + +/** + * Generates a-z from a number 0 to 26 + * + * @memberof Chartist.Core + * @param {Number} n A number from 0 to 26 that will result in a letter a-z + * @return {String} A character from a-z based on the input number n + */ +export function alphaNumerate(n) { + // Limit to a-z + return String.fromCharCode(97 + n % 26); +} diff --git a/src/core/lang.spec.js b/src/core/lang.spec.js new file mode 100644 index 00000000..719a750a --- /dev/null +++ b/src/core/lang.spec.js @@ -0,0 +1,24 @@ +import {quantity} from './lang'; + +describe('Lang', () => { + describe('quantity', () => { + it('should return value for numbers', () => { + expect(quantity(100)).toEqual({value: 100}); + expect(quantity(0)).toEqual({value: 0}); + expect(quantity(NaN)).toEqual({value: NaN}); + expect(quantity(null)).toEqual({value: null}); + expect(quantity(undefined)).toEqual({value: undefined}); + }); + + it('should return value without unit from string', () => { + expect(quantity('100')).toEqual({value: 100, unit: undefined}); + expect(quantity('0')).toEqual({value: 0, unit: undefined}); + }); + + it('should return value and unit from string', () => { + expect(quantity('100%')).toEqual({value: 100, unit: '%'}); + expect(quantity('100 %')).toEqual({value: 100, unit: '%'}); + expect(quantity('0px')).toEqual({value: 0, unit: 'px'}); + }); + }); +}); diff --git a/src/core/math.js b/src/core/math.js new file mode 100644 index 00000000..529906bb --- /dev/null +++ b/src/core/math.js @@ -0,0 +1,95 @@ +import {precision} from './globals'; + +/** + * Calculate the order of magnitude for the chart scale + * + * @memberof Chartist.Core + * @param {Number} value The value Range of the chart + * @return {Number} The order of magnitude + */ +export function orderOfMagnitude(value) { + return Math.floor(Math.log(Math.abs(value)) / Math.LN10); +} + +/** + * Project a data length into screen coordinates (pixels) + * + * @memberof Chartist.Core + * @param {Object} axisLength The svg element for the chart + * @param {Number} length Single data value from a series array + * @param {Object} bounds All the values to set the bounds of the chart + * @return {Number} The projected data length in pixels + */ +export function projectLength(axisLength, length, bounds) { + return length / bounds.range * axisLength; +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param {Number} value The value that should be rounded with precision + * @param {Number} [digits] The number of digits after decimal used to do the rounding + * @returns {number} Rounded value + */ +export function roundWithPrecision(value, digits) { + var precision = Math.pow(10, digits || precision); + return Math.round(value * precision) / precision; +} + +/** + * 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. + * + * @memberof Chartist.Core + * @param {Number} num An integer number where the smallest factor should be searched for + * @returns {Number} The smallest integer factor of the parameter num. + */ +export function rho(num) { + if(num === 1) { + return num; + } + + function gcd(p, q) { + if (p % q === 0) { + return q; + } else { + return gcd(q, p % q); + } + } + + function f(x) { + return x * x + 1; + } + + var x1 = 2, x2 = 2, divisor; + if (num % 2 === 0) { + return 2; + } + + do { + x1 = f(x1) % num; + x2 = f(f(x2)) % num; + divisor = gcd(Math.abs(x1 - x2), num); + } while (divisor === 1); + + return divisor; +} + +/** + * Calculate cartesian coordinates of polar coordinates + * + * @memberof Chartist.Core + * @param {Number} centerX X-axis coordinates of center point of circle segment + * @param {Number} centerY X-axis coordinates of center point of circle segment + * @param {Number} radius Radius of circle segment + * @param {Number} angleInDegrees Angle of circle segment in degrees + * @return {{x:Number, y:Number}} Coordinates of point on circumference + */ +export function polarToCartesian(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; + + return { + x: centerX + (radius * Math.cos(angleInRadians)), + y: centerY + (radius * Math.sin(angleInRadians)) + }; +} diff --git a/src/core/options-provider.js b/src/core/options-provider.js new file mode 100644 index 00000000..18c4a1aa --- /dev/null +++ b/src/core/options-provider.js @@ -0,0 +1,64 @@ +import {extend} from './extend'; + +/** + * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches + * + * @memberof Chartist.Core + * @param {Object} options Options set by user + * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart + * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events + * @return {Object} The consolidated options object from the defaults, base and matching responsive options + */ +export function optionsProvider(options, responsiveOptions, eventEmitter) { + var baseOptions = extend({}, options), + currentOptions, + mediaQueryListeners = [], + i; + + function updateCurrentOptions(mediaEvent) { + var previousOptions = currentOptions; + currentOptions = extend({}, baseOptions); + + if (responsiveOptions) { + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + if (mql.matches) { + currentOptions = extend(currentOptions, responsiveOptions[i][1]); + } + } + } + + if(eventEmitter && mediaEvent) { + eventEmitter.emit('optionsChanged', { + previousOptions: previousOptions, + currentOptions: currentOptions + }); + } + } + + function removeMediaQueryListeners() { + mediaQueryListeners.forEach(function(mql) { + mql.removeListener(updateCurrentOptions); + }); + } + + if (!window.matchMedia) { + throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; + } else if (responsiveOptions) { + + for (i = 0; i < responsiveOptions.length; i++) { + var mql = window.matchMedia(responsiveOptions[i][0]); + mql.addListener(updateCurrentOptions); + mediaQueryListeners.push(mql); + } + } + // Execute initially without an event argument so we get the correct options + updateCurrentOptions(); + + return { + removeMediaQueryListeners: removeMediaQueryListeners, + getCurrentOptions: function getCurrentOptions() { + return extend({}, currentOptions); + } + }; +} diff --git a/src/event/event-emitter.js b/src/event/event-emitter.js new file mode 100644 index 00000000..c00bcf09 --- /dev/null +++ b/src/event/event-emitter.js @@ -0,0 +1,63 @@ +export class EventEmitter { + constructor() { + this.handlers = []; + } + + /** + * Add an event handler for a specific event + * + * @memberof Chartist.Event + * @param {String} event The event name + * @param {Function} handler A event handler function + */ + addEventHandler(event, handler) { + this.handlers[event] = this.handlers[event] || []; + this.handlers[event].push(handler); + } + + /** + * Remove an event handler of a specific event name or remove all event handlers for a specific event. + * + * @memberof Chartist.Event + * @param {String} event The event name where a specific or all handlers should be removed + * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. + */ + removeEventHandler(event, handler) { + // Only do something if there are event handlers with this name existing + if(this.handlers[event]) { + // If handler is set we will look for a specific handler and only remove this + if(handler) { + this.handlers[event].splice(this.handlers[event].indexOf(handler), 1); + if(this.handlers[event].length === 0) { + delete this.handlers[event]; + } + } else { + // If no handler is specified we remove all handlers for this event + delete this.handlers[event]; + } + } + } + + /** + * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. + * + * @memberof Chartist.Event + * @param {String} event The event name that should be triggered + * @param {*} data Arbitrary data that will be passed to the event handler callback functions + */ + emit(event, data) { + // Only do something if there are event handlers with this name existing + if(this.handlers[event]) { + this.handlers[event].forEach(function(handler) { + handler(data); + }); + } + + // Emit event to star event handlers + if(this.handlers['*']) { + this.handlers['*'].forEach(function(starHandler) { + starHandler(event, data); + }); + } + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..b2dad7d9 --- /dev/null +++ b/src/index.js @@ -0,0 +1,11 @@ +export * from './core/core'; +export {EventEmitter} from './event/event-emitter'; +export * from './charts/charts'; +export * from './axes/axes'; +import * as Interpolation from './interpolation/interpolation'; +export { + Interpolation +}; +export * from './svg/svg'; +export * from './svg/svg-list'; +export * from './svg/svg-path'; diff --git a/src/interpolation/cardinal.js b/src/interpolation/cardinal.js new file mode 100644 index 00000000..2c51abab --- /dev/null +++ b/src/interpolation/cardinal.js @@ -0,0 +1,111 @@ +import {extend, splitIntoSegments} from '../core/core'; +import {SvgPath} from '../svg/svg-path'; +import {none} from './none'; + +/** + * 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. + * + * 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`. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.cardinal({ + * tension: 1, + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the cardinal factory function. + * @return {Function} + */ +export function cardinal(options) { + var defaultOptions = { + tension: 1, + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + var t = Math.min(1, Math.max(0, options.tension)), + c = 1 - t; + + return function cardinal(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles + }); + + if(!segments.length) { + // If there were no segments return 'none' interpolation + return none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; + // For each segment we will recurse the cardinal function + segments.forEach(function(segment) { + paths.push(cardinal(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return SvgPath.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; + + // If less than two points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return none()(pathCoordinates, valueData); + } + + var path = new SvgPath().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), + z; + + for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, + {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, + {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, + {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; + } else if (iLen - 4 === i) { + p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + } else if (iLen - 2 === i) { + p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; + p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; + } + } else { + if (iLen - 4 === i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; + } + } + + path.curve( + (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), + (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), + (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), + (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), + p[2].x, + p[2].y, + false, + valueData[(i + 2) / 2] + ); + } + + return path; + } + }; +} diff --git a/src/interpolation/interpolation.js b/src/interpolation/interpolation.js new file mode 100644 index 00000000..439af287 --- /dev/null +++ b/src/interpolation/interpolation.js @@ -0,0 +1,5 @@ +export {none} from './none'; +export {simple} from './simple'; +export {step} from './step'; +export {cardinal} from './cardinal'; +export {monotoneCubic} from './monotone-cubic'; diff --git a/src/interpolation/monotone-cubic.js b/src/interpolation/monotone-cubic.js new file mode 100644 index 00000000..91792330 --- /dev/null +++ b/src/interpolation/monotone-cubic.js @@ -0,0 +1,134 @@ +import {extend, splitIntoSegments} from '../core/core'; +import {SvgPath} from '../svg/svg-path'; +import {none} from './none'; + +/** + * 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. + * + * 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`. + * + * 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. + * + * All smoothing functions within Chartist are factory functions that accept an options parameter. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.monotoneCubic({ + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param {Object} [options] The options of the monotoneCubic factory function. + * @return {Function} + */ +export function monotoneCubic(options) { + var defaultOptions = { + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + return function monotoneCubic(pathCoordinates, valueData) { + // First we try to split the coordinates into segments + // This is necessary to treat "holes" in line charts + var segments = splitIntoSegments(pathCoordinates, valueData, { + fillHoles: options.fillHoles, + increasingX: true + }); + + if(!segments.length) { + // If there were no segments return 'Chartist.Interpolation.none' + return none()([]); + } else if(segments.length > 1) { + // If the split resulted in more that one segment we need to interpolate each segment individually and join them + // afterwards together into a single path. + var paths = []; + // For each segment we will recurse the monotoneCubic fn function + segments.forEach(function(segment) { + paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData)); + }); + // Join the segment path data into a single path and return + return SvgPath.join(paths); + } else { + // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first + // segment + pathCoordinates = segments[0].pathCoordinates; + valueData = segments[0].valueData; + + // If less than three points we need to fallback to no smoothing + if(pathCoordinates.length <= 4) { + return none()(pathCoordinates, valueData); + } + + var xs = [], + ys = [], + i, + n = pathCoordinates.length / 2, + ms = [], + ds = [], dys = [], dxs = [], + path; + + // Populate x and y coordinates into separate arrays, for readability + + for(i = 0; i < n; i++) { + xs[i] = pathCoordinates[i * 2]; + ys[i] = pathCoordinates[i * 2 + 1]; + } + + // Calculate deltas and derivative + + for(i = 0; i < n - 1; i++) { + dys[i] = ys[i + 1] - ys[i]; + dxs[i] = xs[i + 1] - xs[i]; + ds[i] = dys[i] / dxs[i]; + } + + // Determine desired slope (m) at each point using Fritsch-Carlson method + // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation + + ms[0] = ds[0]; + ms[n - 1] = ds[n - 2]; + + for(i = 1; i < n - 1; i++) { + if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) { + ms[i] = 0; + } else { + ms[i] = 3 * (dxs[i - 1] + dxs[i]) / ( + (2 * dxs[i] + dxs[i - 1]) / ds[i - 1] + + (dxs[i] + 2 * dxs[i - 1]) / ds[i]); + + if(!isFinite(ms[i])) { + ms[i] = 0; + } + } + } + + // Now build a path from the slopes + + path = new SvgPath().move(xs[0], ys[0], false, valueData[0]); + + for(i = 0; i < n - 1; i++) { + path.curve( + // First control point + xs[i] + dxs[i] / 3, + ys[i] + ms[i] * dxs[i] / 3, + // Second control point + xs[i + 1] - dxs[i] / 3, + ys[i + 1] - ms[i + 1] * dxs[i] / 3, + // End point + xs[i + 1], + ys[i + 1], + + false, + valueData[i + 1] + ); + } + + return path; + } + }; +} diff --git a/src/interpolation/none.js b/src/interpolation/none.js new file mode 100644 index 00000000..c2e5e6c7 --- /dev/null +++ b/src/interpolation/none.js @@ -0,0 +1,51 @@ +import {extend, getMultiValue} from '../core/core'; +import {SvgPath} from '../svg/svg-path'; + +/** + * This interpolation function does not smooth the path and the result is only containing lines and no curves. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.none({ + * fillHoles: false + * }) + * }); + * + * + * @memberof Chartist.Interpolation + * @return {Function} + */ +export function none(options) { + var defaultOptions = { + fillHoles: false + }; + options = extend({}, defaultOptions, options); + return function none(pathCoordinates, valueData) { + var path = new SvgPath(); + var hole = true; + + for(var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var currData = valueData[i / 2]; + + if(getMultiValue(currData.value) !== undefined) { + + if(hole) { + path.move(currX, currY, false, currData); + } else { + path.line(currX, currY, false, currData); + } + + hole = false; + } else if(!options.fillHoles) { + hole = true; + } + } + + return path; + }; +} diff --git a/src/interpolation/simple.js b/src/interpolation/simple.js new file mode 100644 index 00000000..b3fc806c --- /dev/null +++ b/src/interpolation/simple.js @@ -0,0 +1,73 @@ +import {extend} from '../core/core'; +import {SvgPath} from '../svg/svg-path'; + +/** + * 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. + * + * 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. + * + * 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. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.simple({ + * divisor: 2, + * fillHoles: false + * }) + * }); + * + * + * @memberof Chartist.Interpolation + * @param {Object} options The options of the simple interpolation factory function. + * @return {Function} + */ +export function simple(options) { + var defaultOptions = { + divisor: 2, + fillHoles: false + }; + options = extend({}, defaultOptions, options); + + var d = 1 / Math.max(1, options.divisor); + + return function simple(pathCoordinates, valueData) { + var path = new SvgPath(); + var prevX, prevY, prevData; + + for(var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var length = (currX - prevX) * d; + var currData = valueData[i / 2]; + + if(currData.value !== undefined) { + + if(prevData === undefined) { + path.move(currX, currY, false, currData); + } else { + path.curve( + prevX + length, + prevY, + currX - length, + currY, + currX, + currY, + false, + currData + ); + } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if(!options.fillHoles) { + prevX = currX = prevData = undefined; + } + } + + return path; + }; +} diff --git a/src/interpolation/step.js b/src/interpolation/step.js new file mode 100644 index 00000000..8fadea0e --- /dev/null +++ b/src/interpolation/step.js @@ -0,0 +1,68 @@ +import {extend} from '../core/core'; +import {SvgPath} from '../svg/svg-path'; + +/** + * 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. + * + * 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`. + * + * @example + * var chart = new Chartist.Line('.ct-chart', { + * labels: [1, 2, 3, 4, 5], + * series: [[1, 2, 8, 1, 7]] + * }, { + * lineSmooth: Chartist.Interpolation.step({ + * postpone: true, + * fillHoles: false + * }) + * }); + * + * @memberof Chartist.Interpolation + * @param options + * @returns {Function} + */ +export function step(options) { + var defaultOptions = { + postpone: true, + fillHoles: false + }; + + options = extend({}, defaultOptions, options); + + return function step(pathCoordinates, valueData) { + var path = new SvgPath(); + + var prevX, prevY, prevData; + + for (var i = 0; i < pathCoordinates.length; i += 2) { + var currX = pathCoordinates[i]; + var currY = pathCoordinates[i + 1]; + var currData = valueData[i / 2]; + + // If the current point is also not a hole we can draw the step lines + if(currData.value !== undefined) { + if(prevData === undefined) { + path.move(currX, currY, false, currData); + } else { + if(options.postpone) { + // If postponed we should draw the step line with the value of the previous value + path.line(currX, prevY, false, prevData); + } else { + // If not postponed we should draw the step line with the value of the current value + path.line(prevX, currY, false, currData); + } + // Line to the actual point (this should only be a Y-Axis movement + path.line(currX, currY, false, currData); + } + + prevX = currX; + prevY = currY; + prevData = currData; + } else if(!options.fillHoles) { + prevX = prevY = prevData = undefined; + } + } + + return path; + }; +} diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss new file mode 100644 index 00000000..e3caaa6b --- /dev/null +++ b/src/styles/chartist.scss @@ -0,0 +1,241 @@ +@import "http://github.com/settings/chartist-settings"; + +@mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) { + display: block; + position: relative; + width: $width; + + &:before { + display: block; + float: left; + content: ""; + width: 0; + height: 0; + padding-bottom: $ratio * 100%; + } + + &:after { + content: ""; + display: table; + clear: both; + } + + > svg { + display: block; + position: absolute; + top: 0; + left: 0; + } +} + +@mixin ct-align-justify($ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) { + -webkit-box-align: $ct-text-align; + -webkit-align-items: $ct-text-align; + -ms-flex-align: $ct-text-align; + align-items: $ct-text-align; + -webkit-box-pack: $ct-text-justify; + -webkit-justify-content: $ct-text-justify; + -ms-flex-pack: $ct-text-justify; + justify-content: $ct-text-justify; + // Fallback to text-align for non-flex browsers + @if($ct-text-justify == 'flex-start') { + text-align: left; + } @else if ($ct-text-justify == 'flex-end') { + text-align: right; + } @else { + text-align: center; + } +} + +@mixin ct-flex() { + // Fallback to block + display: block; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; +} + +@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) { + fill: $ct-text-color; + color: $ct-text-color; + font-size: $ct-text-size; + line-height: $ct-text-line-height; +} + +@mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { + stroke: $ct-grid-color; + stroke-width: $ct-grid-width; + + @if ($ct-grid-dasharray) { + stroke-dasharray: $ct-grid-dasharray; + } +} + +@mixin ct-chart-point($ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape) { + stroke-width: $ct-point-size; + stroke-linecap: $ct-point-shape; +} + +@mixin ct-chart-line($ct-line-width: $ct-line-width, $ct-line-dasharray: $ct-line-dasharray) { + fill: none; + stroke-width: $ct-line-width; + + @if ($ct-line-dasharray) { + stroke-dasharray: $ct-line-dasharray; + } +} + +@mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) { + stroke: none; + fill-opacity: $ct-area-opacity; +} + +@mixin ct-chart-bar($ct-bar-width: $ct-bar-width) { + fill: none; + stroke-width: $ct-bar-width; +} + +@mixin ct-chart-donut($ct-donut-width: $ct-donut-width) { + fill: none; + stroke-width: $ct-donut-width; +} + +@mixin ct-chart-series-color($color) { + .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice-donut} { + stroke: $color; + } + + .#{$ct-class-slice-pie}, .#{$ct-class-area} { + fill: $color; + } +} + +@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { + + .#{$ct-class-label} { + @include ct-chart-label($ct-text-color, $ct-text-size); + } + + .#{$ct-class-chart-line} .#{$ct-class-label}, + .#{$ct-class-chart-bar} .#{$ct-class-label} { + @include ct-flex(); + } + + .#{$ct-class-chart-pie} .#{$ct-class-label}, + .#{$ct-class-chart-donut} .#{$ct-class-label} { + dominant-baseline: central; + } + + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-end); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; + } + + .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { + @include ct-align-justify(flex-end, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, center); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, center); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { + @include ct-align-justify(flex-end, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { + @include ct-align-justify(flex-start, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: start; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { + //@include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify); + @include ct-align-justify(center, flex-end); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; + } + + .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { + @include ct-align-justify(center, flex-start); + // Fallback for browsers that don't support foreignObjects + text-anchor: end; + } + + .#{$ct-class-grid} { + @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); + } + + .#{$ct-class-grid-background} { + fill: $ct-grid-background-fill; + } + + .#{$ct-class-point} { + @include ct-chart-point($ct-point-size, $ct-point-shape); + } + + .#{$ct-class-line} { + @include ct-chart-line($ct-line-width); + } + + .#{$ct-class-area} { + @include ct-chart-area(); + } + + .#{$ct-class-bar} { + @include ct-chart-bar($ct-bar-width); + } + + .#{$ct-class-slice-donut} { + @include ct-chart-donut($ct-donut-width); + } + + @if $ct-include-colored-series { + @for $i from 0 to length($ct-series-names) { + .#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { + $color: nth($ct-series-colors, $i + 1); + + @include ct-chart-series-color($color); + } + } + } +} + +@if $ct-include-classes { + @include ct-chart(); + + @if $ct-include-alternative-responsive-containers { + @for $i from 0 to length($ct-scales-names) { + .#{nth($ct-scales-names, $i + 1)} { + @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); + } + } + } +} diff --git a/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss new file mode 100644 index 00000000..4d0370eb --- /dev/null +++ b/src/styles/settings/_chartist-settings.scss @@ -0,0 +1,87 @@ +// Scales for responsive SVG containers +$ct-scales: ((1), (15/16), (8/9), (5/6), (4/5), (3/4), (2/3), (5/8), (1/1.618), (3/5), (9/16), (8/15), (1/2), (2/5), (3/8), (1/3), (1/4)) !default; +$ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, ct-major-third, ct-perfect-fourth, ct-perfect-fifth, ct-minor-sixth, ct-golden-section, ct-major-sixth, ct-minor-seventh, ct-major-seventh, ct-octave, ct-major-tenth, ct-major-eleventh, ct-major-twelfth, ct-double-octave) !default; + +// Class names to be used when generating CSS +$ct-class-chart: ct-chart !default; +$ct-class-chart-line: ct-chart-line !default; +$ct-class-chart-bar: ct-chart-bar !default; +$ct-class-horizontal-bars: ct-horizontal-bars !default; +$ct-class-chart-pie: ct-chart-pie !default; +$ct-class-chart-donut: ct-chart-donut !default; +$ct-class-label: ct-label !default; +$ct-class-series: ct-series !default; +$ct-class-line: ct-line !default; +$ct-class-point: ct-point !default; +$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-grid: ct-grid !default; +$ct-class-grid-background: ct-grid-background !default; +$ct-class-vertical: ct-vertical !default; +$ct-class-horizontal: ct-horizontal !default; +$ct-class-start: ct-start !default; +$ct-class-end: ct-end !default; + +// Container ratio +$ct-container-ratio: (1/1.618) !default; + +// Text styles for labels +$ct-text-color: rgba(0, 0, 0, 0.4) !default; +$ct-text-size: 0.75rem !default; +$ct-text-align: flex-start !default; +$ct-text-justify: flex-start !default; +$ct-text-line-height: 1; + +// Grid styles +$ct-grid-color: rgba(0, 0, 0, 0.2) !default; +$ct-grid-dasharray: 2px !default; +$ct-grid-width: 1px !default; +$ct-grid-background-fill: none !default; + +// Line chart properties +$ct-line-width: 4px !default; +$ct-line-dasharray: false !default; +$ct-point-size: 10px !default; +// Line chart point, can be either round or square +$ct-point-shape: round !default; +// Area fill transparency between 0 and 1 +$ct-area-opacity: 0.1 !default; + +// Bar chart bar width +$ct-bar-width: 10px !default; + +// Donut width (If donut width is to big it can cause issues where the shape gets distorted) +$ct-donut-width: 60px !default; + +// If set to true it will include the default classes and generate CSS output. If you're planning to use the mixins you +// should set this property to false +$ct-include-classes: true !default; + +// If this is set to true the CSS will contain colored series. You can extend or change the color with the +// properties below +$ct-include-colored-series: $ct-include-classes !default; + +// If set to true this will include all responsive container variations using the scales defined at the top of the script +$ct-include-alternative-responsive-containers: $ct-include-classes !default; + +// Series names and colors. This can be extended or customized as desired. Just add more series and colors. +$ct-series-names: (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) !default; +$ct-series-colors: ( + #d70206, + #f05b4f, + #f4c63d, + #d17905, + #453d3f, + #59922b, + #0544d3, + #6b0392, + #f05b4f, + #dda458, + #eacf7d, + #86797d, + #b2c326, + #6188e2, + #a748ca +) !default; diff --git a/src/svg/svg-list.js b/src/svg/svg-list.js new file mode 100644 index 00000000..b56d40b6 --- /dev/null +++ b/src/svg/svg-list.js @@ -0,0 +1,41 @@ +import {Svg} from './svg'; + +/** + * This helper class is to wrap multiple `Svg` elements into a list where you can call the `Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Svg` on multiple elements. + * An instance of this class is also returned by `Svg.querySelectorAll`. + * + * @memberof Svg + * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) + * @constructor + */ +export class SvgList { + constructor(nodeList) { + var list = this; + + this.svgElements = []; + for(var i = 0; i < nodeList.length; i++) { + this.svgElements.push(new Svg(nodeList[i])); + } + + // Add delegation methods for Svg + Object.keys(Svg.prototype).filter(function(prototypeProperty) { + return ['constructor', + 'parent', + 'querySelector', + 'querySelectorAll', + 'replace', + 'append', + 'classes', + 'height', + 'width'].indexOf(prototypeProperty) === -1; + }).forEach(function(prototypeProperty) { + list[prototypeProperty] = function() { + var args = Array.prototype.slice.call(arguments, 0); + list.svgElements.forEach(function(element) { + Svg.prototype[prototypeProperty].apply(element, args); + }); + return list; + }; + }); + } +} diff --git a/src/svg/svg-path.js b/src/svg/svg-path.js new file mode 100644 index 00000000..d634d9ee --- /dev/null +++ b/src/svg/svg-path.js @@ -0,0 +1,358 @@ +import {extend} from '../core/core'; + +/** + * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported. + * + * @memberof SvgPath + * @type {Object} + */ +const elementDescriptions = { + m: ['x', 'y'], + l: ['x', 'y'], + c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'], + a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y'] +}; + +/** + * Default options for newly created SVG path objects. + * + * @memberof SvgPath + * @type {Object} + */ +const defaultOptions = { + // 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. + accuracy: 3 +}; + +function element(command, params, pathElements, pos, relative, data) { + var pathElement = extend({ + command: relative ? command.toLowerCase() : command.toUpperCase() + }, params, data ? { data: data } : {} ); + + pathElements.splice(pos, 0, pathElement); +} + +function forEachParam(pathElements, cb) { + pathElements.forEach(function(pathElement, pathElementIndex) { + elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) { + cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + }); + }); +} + +/** + * Used to construct a new path object. + * + * @memberof SvgPath + * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end) + * @param {Object} options Options object that overrides the default objects. See default options for more details. + * @constructor + */ +export class SvgPath { + /** + * This static function on `SvgPath` is joining multiple paths together into one paths. + * + * @memberof SvgPath + * @param {Array} paths A list of paths to be joined together. The order is important. + * @param {boolean} [close] If the newly created path should be a closed path + * @param {Object} [options] Path options for the newly created path. + * @return {SvgPath} + */ + static join(paths, close, options) { + var joinedPath = new SvgPath(close, options); + for(var i = 0; i < paths.length; i++) { + var path = paths[i]; + for(var j = 0; j < path.pathElements.length; j++) { + joinedPath.pathElements.push(path.pathElements[j]); + } + } + return joinedPath; + } + + constructor(close, options) { + this.pathElements = []; + this.pos = 0; + this.close = close; + this.options = extend({}, defaultOptions, options); + } + + /** + * 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. + * + * @memberof SvgPath + * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array. + * @return {SvgPath|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. + */ + position(pos) { + if(pos !== undefined) { + this.pos = Math.max(0, Math.min(this.pathElements.length, pos)); + return this; + } else { + return this.pos; + } + } + + /** + * Removes elements from the path starting at the current position. + * + * @memberof SvgPath + * @param {Number} count Number of path elements that should be removed from the current position. + * @return {SvgPath} The current path object for easy call chaining. + */ + remove(count) { + this.pathElements.splice(this.pos, count); + return this; + } + + /** + * Use this function to add a new move SVG path element. + * + * @memberof SvgPath + * @param {Number} x The x coordinate for the move element. + * @param {Number} y The y coordinate for the move element. + * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + move(x, y, relative, data) { + element('M', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * Use this function to add a new line SVG path element. + * + * @memberof SvgPath + * @param {Number} x The x coordinate for the line element. + * @param {Number} y The y coordinate for the line element. + * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + line(x, y, relative, data) { + element('L', { + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * Use this function to add a new curve SVG path element. + * + * @memberof SvgPath + * @param {Number} x1 The x coordinate for the first control point of the bezier curve. + * @param {Number} y1 The y coordinate for the first control point of the bezier curve. + * @param {Number} x2 The x coordinate for the second control point of the bezier curve. + * @param {Number} y2 The y coordinate for the second control point of the bezier curve. + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + curve(x1, y1, x2, y2, x, y, relative, data) { + element('C', { + x1: +x1, + y1: +y1, + x2: +x2, + y2: +y2, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * Use this function to add a new non-bezier curve SVG path element. + * + * @memberof SvgPath + * @param {Number} rx The radius to be used for the x-axis of the arc. + * @param {Number} ry The radius to be used for the y-axis of the arc. + * @param {Number} xAr Defines the orientation of the arc + * @param {Number} lAf Large arc flag + * @param {Number} sf Sweep flag + * @param {Number} x The x coordinate for the target point of the curve element. + * @param {Number} y The y coordinate for the target point of the curve element. + * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) + * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement + * @return {SvgPath} The current path object for easy call chaining. + */ + arc(rx, ry, xAr, lAf, sf, x, y, relative, data) { + element('A', { + rx: +rx, + ry: +ry, + xAr: +xAr, + lAf: +lAf, + sf: +sf, + x: +x, + y: +y + }, this.pathElements, this.pos++, relative, data); + return this; + } + + /** + * 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. + * + * @memberof SvgPath + * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components. + * @return {SvgPath} The current path object for easy call chaining. + */ + parse(path) { + // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] + var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') + .replace(/([0-9])([A-Za-z])/g, '$1 $2') + .split(/[\s,]+/) + .reduce(function(result, element) { + if(element.match(/[A-Za-z]/)) { + result.push([]); + } + + result[result.length - 1].push(element); + return result; + }, []); + + // If this is a closed path we remove the Z at the end because this is determined by the close option + if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') { + chunks.pop(); + } + + // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters + // For example {command: 'M', x: '10', y: '10'} + var elements = chunks.map(function(chunk) { + var command = chunk.shift(), + description = elementDescriptions[command.toLowerCase()]; + + return extend({ + command: command + }, description.reduce(function(result, paramName, index) { + result[paramName] = +chunk[index]; + return result; + }, {})); + }); + + // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position + var spliceArgs = [this.pos, 0]; + Array.prototype.push.apply(spliceArgs, elements); + Array.prototype.splice.apply(this.pathElements, spliceArgs); + // Increase the internal position by the element count + this.pos += elements.length; + + return this; + } + + /** + * 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. + * + * @memberof SvgPath + * @return {String} + */ + stringify() { + var accuracyMultiplier = Math.pow(10, this.options.accuracy); + + return this.pathElements.reduce(function(path, pathElement) { + var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) { + return this.options.accuracy ? + (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) : + pathElement[paramName]; + }.bind(this)); + + return path + pathElement.command + params.join(','); + }.bind(this), '') + (this.close ? 'Z' : ''); + } + + /** + * 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. + * + * @memberof SvgPath + * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements. + * @return {SvgPath} The current path object for easy call chaining. + */ + scale(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] *= paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * + * @memberof SvgPath + * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements. + * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements. + * @return {SvgPath} The current path object for easy call chaining. + */ + translate(x, y) { + forEachParam(this.pathElements, function(pathElement, paramName) { + pathElement[paramName] += paramName[0] === 'x' ? x : y; + }); + return this; + } + + /** + * 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. + * The method signature of the callback function looks like this: + * ```javascript + * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) + * ``` + * 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. + * + * @memberof SvgPath + * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description. + * @return {SvgPath} The current path object for easy call chaining. + */ + transform(transformFnc) { + forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) { + var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + if(transformed || transformed === 0) { + pathElement[paramName] = transformed; + } + }); + return this; + } + + /** + * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. + * + * @memberof SvgPath + * @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. + * @return {SvgPath} + */ + clone(close) { + var c = new SvgPath(close || this.close); + c.pos = this.pos; + c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { + return extend({}, pathElement); + }); + c.options = extend({}, this.options); + return c; + } + + /** + * 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. + * + * @memberof SvgPath + * @param {String} command The command you'd like to use to split the path + * @return {Array} + */ + splitByCommand(command) { + var split = [ + new SvgPath() + ]; + + this.pathElements.forEach(function(pathElement) { + if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) { + split.push(new SvgPath()); + } + + split[split.length - 1].pathElements.push(pathElement); + }); + + return split; + } +} diff --git a/src/svg/svg.js b/src/svg/svg.js new file mode 100644 index 00000000..cc605f06 --- /dev/null +++ b/src/svg/svg.js @@ -0,0 +1,525 @@ +import {namespaces, ensureUnit, quantity, extend} from '../core/core'; +import {SvgList} from './svg-list'; + +/** + * Svg creates a new SVG object wrapper with a starting element. You can use the wrapper to fluently create sub-elements and modify them. + * + * @memberof Svg + * @constructor + * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Svg + * @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. + * @param {String} className This class or class list will be added to the SVG element + * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child + * @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 + */ +export class Svg { + + constructor(name, attributes, className, parent, insertFirst) { + // If Svg is getting called with an SVG element we just return the wrapper + if(name instanceof Element) { + this._node = name; + } else { + this._node = document.createElementNS(namespaces.svg, name); + + // If this is an SVG element created then custom namespace + if(name === 'svg') { + this.attr({ + 'xmlns:ct': namespaces.ct + }); + } + } + + if(attributes) { + this.attr(attributes); + } + + if(className) { + this.addClass(className); + } + + if(parent) { + if (insertFirst && parent._node.firstChild) { + parent._node.insertBefore(this._node, parent._node.firstChild); + } else { + parent._node.appendChild(this._node); + } + } + } + + /** + * Set attributes on the current SVG element of the wrapper you're currently working on. + * + * @memberof Svg + * @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. + * @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. + * @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. + */ + attr(attributes, ns) { + if(typeof attributes === 'string') { + if(ns) { + return this._node.getAttributeNS(ns, attributes); + } else { + return this._node.getAttribute(attributes); + } + } + + Object.keys(attributes).forEach(function(key) { + // If the attribute value is undefined we can skip this one + if(attributes[key] === undefined) { + return; + } + + if (key.indexOf(':') !== -1) { + var namespacedAttribute = key.split(':'); + this._node.setAttributeNS(namespaces[namespacedAttribute[0]], key, attributes[key]); + } else { + this._node.setAttribute(key, attributes[key]); + } + }.bind(this)); + + return this; + } + + /** + * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. + * + * @memberof Svg + * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @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 + * @return {Svg} Returns a Svg wrapper object that can be used to modify the containing SVG data + */ + elem(name, attributes, className, insertFirst) { + return new Svg(name, attributes, className, this, insertFirst); + } + + /** + * Returns the parent Chartist.SVG wrapper object + * + * @memberof Svg + * @return {Svg} Returns a 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. + */ + parent() { + return this._node.parentNode instanceof SVGElement ? new Svg(this._node.parentNode) : null; + } + + /** + * This method returns a Svg wrapper around the root SVG element of the current tree. + * + * @memberof Svg + * @return {Svg} The root SVG element wrapped in a Svg element + */ + root() { + var node = this._node; + while(node.nodeName !== 'svg') { + node = node.parentNode; + } + return new Svg(node); + } + + /** + * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Svg wrapper. + * + * @memberof Svg + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @return {Svg} The SVG wrapper for the element found or null if no element was found + */ + querySelector(selector) { + var foundNode = this._node.querySelector(selector); + return foundNode ? new Svg(foundNode) : null; + } + + /** + * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Svg.List wrapper. + * + * @memberof Svg + * @param {String} selector A CSS selector that is used to query for child SVG elements + * @return {SvgList} The SVG wrapper list for the element found or null if no element was found + */ + querySelectorAll(selector) { + var foundNodes = this._node.querySelectorAll(selector); + return foundNodes.length ? new SvgList(foundNodes) : null; + } + + /** + * Returns the underlying SVG node for the current element. + * + * @memberof Svg + * @returns {Node} + */ + getNode() { + return this._node; + } + + /** + * 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. + * + * @memberof Svg + * @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 + * @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. + * @param {String} [className] This class or class list will be added to the SVG element + * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child + * @return {Svg} New wrapper object that wraps the foreignObject element + */ + foreignObject(content, attributes, className, insertFirst) { + // If content is string then we convert it to DOM + // TODO: Handle case where content is not a string nor a DOM Node + if(typeof content === 'string') { + var container = document.createElement('div'); + container.innerHTML = content; + content = container.firstChild; + } + + // Adding namespace to content element + content.setAttribute('xmlns', namespaces.xmlns); + + // Creating the foreignObject without required extension attribute (as described here + // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) + var fnObj = this.elem('foreignObject', attributes, className, insertFirst); + + // Add content to foreignObjectElement + fnObj._node.appendChild(content); + + return fnObj; + } + + /** + * This method adds a new text element to the current Svg wrapper. + * + * @memberof Svg + * @param {String} t The text that should be added to the text element that is created + * @return {Svg} The same wrapper object that was used to add the newly created element + */ + text(t) { + this._node.appendChild(document.createTextNode(t)); + return this; + } + + /** + * This method will clear all child nodes of the current wrapper object. + * + * @memberof Svg + * @return {Svg} The same wrapper object that got emptied + */ + empty() { + while (this._node.firstChild) { + this._node.removeChild(this._node.firstChild); + } + + return this; + } + + /** + * 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. + * + * @memberof Svg + * @return {Svg} The parent wrapper object of the element that got removed + */ + remove() { + this._node.parentNode.removeChild(this._node); + return this.parent(); + } + + /** + * This method will replace the element with a new element that can be created outside of the current DOM. + * + * @memberof Svg + * @param {Svg} newElement The new Svg object that will be used to replace the current wrapper object + * @return {Svg} The wrapper of the new element + */ + replace(newElement) { + this._node.parentNode.replaceChild(newElement._node, this._node); + return newElement; + } + + /** + * This method will append an element to the current element as a child. + * + * @memberof Svg + * @param {Svg} element The Svg element that should be added as a child + * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child + * @return {Svg} The wrapper of the appended object + */ + append(element, insertFirst) { + if(insertFirst && this._node.firstChild) { + this._node.insertBefore(element._node, this._node.firstChild); + } else { + this._node.appendChild(element._node); + } + + return this; + } + + /** + * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. + * + * @memberof Svg + * @return {Array} A list of classes or an empty array if there are no classes on the current element + */ + classes() { + return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; + } + + /** + * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. + * + * @memberof Svg + * @param {String} names A white space separated list of class names + * @return {Svg} The wrapper of the current element + */ + addClass(names) { + this._node.setAttribute('class', + this.classes() + .concat(names.trim().split(/\s+/)) + .filter(function(elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ') + ); + + return this; + } + + /** + * Removes one or a space separated list of classes from the current element. + * + * @memberof Svg + * @param {String} names A white space separated list of class names + * @return {Svg} The wrapper of the current element + */ + removeClass(names) { + var removedClasses = names.trim().split(/\s+/); + + this._node.setAttribute('class', this.classes().filter(function(name) { + return removedClasses.indexOf(name) === -1; + }).join(' ')); + + return this; + } + + /** + * Removes all classes from the current element. + * + * @memberof Svg + * @return {Svg} The wrapper of the current element + */ + removeAllClasses() { + this._node.setAttribute('class', ''); + return this; + } + + /** + * Get element height using `getBoundingClientRect` + * + * @memberof Svg + * @return {Number} The elements height in pixels + */ + height() { + return this._node.getBoundingClientRect().height; + } + + /** + * Get element width using `getBoundingClientRect` + * + * @memberof Chartist.Core + * @return {Number} The elements width in pixels + */ + width() { + return this._node.getBoundingClientRect().width; + } + + /** + * 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 `Svg.Easing` or an array with four numbers specifying a cubic Bézier curve. + * **An animations object could look like this:** + * ```javascript + * element.animate({ + * opacity: { + * dur: 1000, + * from: 0, + * to: 1 + * }, + * x1: { + * dur: '1000ms', + * from: 100, + * to: 200, + * easing: 'easeOutQuart' + * }, + * y1: { + * dur: '2s', + * from: 0, + * to: 100 + * } + * }); + * ``` + * **Automatic unit conversion** + * 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. + * **Guided mode** + * 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 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. + * If guided mode is enabled the following behavior is added: + * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation + * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) + * - The animate element will be forced to use `fill="freeze"` + * - 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. + * - After the animation the element attribute value will be set to the `to` value of the animation + * - The animate element is deleted from the DOM + * + * @memberof Svg + * @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. + * @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. + * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. + * @return {Svg} The current element where the animation was added + */ + animate(animations, guided, eventEmitter) { + if(guided === undefined) { + guided = true; + } + + Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + + function createAnimate(animationDefinition, guided) { + var attributeProperties = {}, + animate, + timeout, + animationEasing; + + // Check if an easing is specified in the definition object and delete it from the object as it will not + // be part of the animate element attributes. + if(animationDefinition.easing) { + // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object + animationEasing = animationDefinition.easing instanceof Array ? + animationDefinition.easing : + easings[animationDefinition.easing]; + delete animationDefinition.easing; + } + + // If numeric dur or begin was provided we assume milli seconds + animationDefinition.begin = ensureUnit(animationDefinition.begin, 'ms'); + animationDefinition.dur = ensureUnit(animationDefinition.dur, 'ms'); + + if(animationEasing) { + animationDefinition.calcMode = 'spline'; + animationDefinition.keySplines = animationEasing.join(' '); + animationDefinition.keyTimes = '0;1'; + } + + // Adding "fill: freeze" if we are in guided mode and set initial attribute values + if(guided) { + animationDefinition.fill = 'freeze'; + // Animated property on our element should already be set to the animation from value in guided mode + attributeProperties[attribute] = animationDefinition.from; + this.attr(attributeProperties); + + // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin + // which needs to be in ms aside + timeout = quantity(animationDefinition.begin || 0).value; + animationDefinition.begin = 'indefinite'; + } + + animate = this.elem('animate', extend({ + attributeName: attribute + }, animationDefinition)); + + if(guided) { + // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout + setTimeout(function() { + // If beginElement fails we set the animated attribute to the end position and remove the animate element + // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in + // the browser. (Currently FF 34 does not support animate elements in foreignObjects) + try { + animate._node.beginElement(); + } catch(err) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this), timeout); + } + + if(eventEmitter) { + animate._node.addEventListener('beginEvent', function handleBeginEvent() { + eventEmitter.emit('animationBegin', { + element: this, + animate: animate._node, + params: animationDefinition + }); + }.bind(this)); + } + + animate._node.addEventListener('endEvent', function handleEndEvent() { + if(eventEmitter) { + eventEmitter.emit('animationEnd', { + element: this, + animate: animate._node, + params: animationDefinition + }); + } + + if(guided) { + // Set animated attribute to current animated value + attributeProperties[attribute] = animationDefinition.to; + this.attr(attributeProperties); + // Remove the animate element as it's no longer required + animate.remove(); + } + }.bind(this)); + } + + // If current attribute is an array of definition objects we create an animate for each and disable guided mode + if(animations[attribute] instanceof Array) { + animations[attribute].forEach(function(animationDefinition) { + createAnimate.bind(this)(animationDefinition, false); + }.bind(this)); + } else { + createAnimate.bind(this)(animations[attribute], guided); + } + + }.bind(this)); + + return this; + } +} + +/** + * 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. + * + * @memberof Svg + * @param {String} feature The SVG 1.1 feature that should be checked for support. + * @return {Boolean} True of false if the feature is supported or not + */ +export function isSupported(feature) { + return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1'); +} + +/** + * This Object contains some standard easing cubic bezier curves. Then can be used with their name in the `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. + * + * @memberof Svg + */ +export const easings = { + easeInSine: [0.47, 0, 0.745, 0.715], + easeOutSine: [0.39, 0.575, 0.565, 1], + easeInOutSine: [0.445, 0.05, 0.55, 0.95], + easeInQuad: [0.55, 0.085, 0.68, 0.53], + easeOutQuad: [0.25, 0.46, 0.45, 0.94], + easeInOutQuad: [0.455, 0.03, 0.515, 0.955], + easeInCubic: [0.55, 0.055, 0.675, 0.19], + easeOutCubic: [0.215, 0.61, 0.355, 1], + easeInOutCubic: [0.645, 0.045, 0.355, 1], + easeInQuart: [0.895, 0.03, 0.685, 0.22], + easeOutQuart: [0.165, 0.84, 0.44, 1], + easeInOutQuart: [0.77, 0, 0.175, 1], + easeInQuint: [0.755, 0.05, 0.855, 0.06], + easeOutQuint: [0.23, 1, 0.32, 1], + easeInOutQuint: [0.86, 0, 0.07, 1], + easeInExpo: [0.95, 0.05, 0.795, 0.035], + easeOutExpo: [0.19, 1, 0.22, 1], + easeInOutExpo: [1, 0, 0, 1], + easeInCirc: [0.6, 0.04, 0.98, 0.335], + easeOutCirc: [0.075, 0.82, 0.165, 1], + easeInOutCirc: [0.785, 0.135, 0.15, 0.86], + easeInBack: [0.6, -0.28, 0.735, 0.045], + easeOutBack: [0.175, 0.885, 0.32, 1.275], + easeInOutBack: [0.68, -0.55, 0.265, 1.55] +}; diff --git a/src/testing/fixtures.js b/src/testing/fixtures.js new file mode 100644 index 00000000..8501638d --- /dev/null +++ b/src/testing/fixtures.js @@ -0,0 +1,37 @@ +export let container = null; + +export function initializeFixtures() { + if (!container) { + container = document.createElement('div'); + container.setAttribute('data-fixture-container', `${+new Date()}`); + document.body.appendChild(container); + } +} + +export function destroyFixtures() { + if (container) { + document.body.removeChild(container); + container = null; + } + } + +export function loadFixture(path) { + if (!container) { + initializeFixtures(); + } + + return SystemJS.import(path).then((module) => { + return addFixture(module.default || module); + }); +} + +export function addFixture(fixture) { + const wrapper = document.createElement('div'); + wrapper.innerHTML += fixture; + container.appendChild(wrapper); + return { + wrapper, + container, + fixture + }; +} diff --git a/src/testing/jasmine-dom-matchers.js b/src/testing/jasmine-dom-matchers.js new file mode 100644 index 00000000..d09c4b2c --- /dev/null +++ b/src/testing/jasmine-dom-matchers.js @@ -0,0 +1,35 @@ +function createCustomMatchers(matchers) { + return Object.keys(matchers).reduce((customMatchers, matcherName) => { + customMatchers[matcherName] = (util, customEqualityTesters) => { + return { + compare: (actual, expected) => { + return matchers[matcherName](actual, expected, util, customEqualityTesters); + } + }; + }; + return customMatchers; + }, {}); +} + +const domMatchers = { + toHaveClass(actual, expected) { + console.log(actual); + console.log(expected); + + const pass = actual.classList.contains(expected); + return { + pass, + message: `Expected ${actual.classList} to contain ${expected}` + }; + }, + + toContainElement(actual, expected) { + const pass = !!actual.querySelector(expected); + return { + pass, + message: `Expected ${actual} to contain element with selector ${expected}` + }; + } +}; + +beforeEach(() => jasmine.addMatchers(createCustomMatchers(domMatchers))); diff --git a/src/testing/spec/fixture-with-multiple-elements.html b/src/testing/spec/fixture-with-multiple-elements.html new file mode 100644 index 00000000..bcefe8be --- /dev/null +++ b/src/testing/spec/fixture-with-multiple-elements.html @@ -0,0 +1 @@ +

    First element-

    Second element-

    Third element
    diff --git a/src/testing/spec/fixture-with-single-element.html b/src/testing/spec/fixture-with-single-element.html new file mode 100644 index 00000000..8bb33e88 --- /dev/null +++ b/src/testing/spec/fixture-with-single-element.html @@ -0,0 +1 @@ +

    This is a test fixture

    diff --git a/src/testing/spec/fixtures.spec.js b/src/testing/spec/fixtures.spec.js new file mode 100644 index 00000000..3cbb3b3f --- /dev/null +++ b/src/testing/spec/fixtures.spec.js @@ -0,0 +1,47 @@ +import {loadFixture, destroyFixtures, initializeFixtures, container} from '../fixtures'; + +describe('Fixtures', () => { + beforeEach(() => initializeFixtures()); + afterEach(() => destroyFixtures()); + + it('should initialize correctly and add container to body', () => { + initializeFixtures(); + expect(document.querySelector('[data-fixture-container]')).toBe(container); + expect(container.parentNode).toBe(document.body); + }); + + it('should destroy correctly and remove any existing container', () => { + initializeFixtures(); + destroyFixtures(); + expect(document.querySelector('[data-fixture-container]')).toBeFalsy(); + expect(container).toBeFalsy(); + }); + + it('should load fixtures with single element and set wrapper, fixture and container correctly', (done) => { + loadFixture('chartist/testing/spec/fixture-with-single-element.html!text').then((context) => { + expect(context.container).toBe(container); + expect(context.wrapper.textContent.trim()).toBe('This is a test fixture'); + expect(context.fixture.trim()).toBe('

    This is a test fixture

    '); + done(); + }); + }); + + it('should load fixtures with multiple elements', (done) => { + loadFixture('/src/testing/spec/fixture-with-multiple-elements.html!text').then((context) => { + expect(context.container.textContent.trim()).toBe('First element-Second element-Third element'); + done(); + }); + }); + + it('should load multiple fixtures correctly', (done) => { + Promise.all([ + loadFixture('/src/testing/spec/fixture-with-single-element.html!text'), + loadFixture('/src/testing/spec/fixture-with-multiple-elements.html!text') + ]).then(() => { + expect(container.childNodes.length).toBe(2); + expect(container.childNodes[0].textContent.trim()).toBe('This is a test fixture'); + expect(container.childNodes[1].textContent.trim()).toBe('First element-Second element-Third element'); + done(); + }); + }); +}); diff --git a/tooling/node/banner.js b/tooling/node/banner.js new file mode 100755 index 00000000..549b8fb3 --- /dev/null +++ b/tooling/node/banner.js @@ -0,0 +1,12 @@ +#!/usr/bin/env node + +const fsp = require('fs-promise'); +const interpolate = require('interpolate'); +const pkg = require('../../package.json'); +let content = interpolate(pkg.config.banner, { + pkg, + year: new Date().getFullYear() +}); + +fsp.readFile(process.argv[2]) + .then((data) => fsp.writeFile(process.argv[3], content + data)); diff --git a/tooling/node/compile-sass.js b/tooling/node/compile-sass.js new file mode 100644 index 00000000..7849601e --- /dev/null +++ b/tooling/node/compile-sass.js @@ -0,0 +1,50 @@ +function compileSass(inFilePath, outDirectoryPath) { + const sass = require('node-sass'); + const postcss = require('postcss'); + const fsp = require('fs-promise'); + const path = require('path'); + const baseFileName = path.basename(inFilePath, '.scss'); + const cssBaseName = `${baseFileName}.css`; + const cssMapBaseName = `${baseFileName}.css.map`; + const cssMinBaseName = `${baseFileName}.min.css`; + const cssMinMapBaseName = `${baseFileName}.min.css.map`; + + sass.render({ + file: inFilePath, + sourceMap: true, + outFile: cssBaseName + }, (err, result) => { + postcss([require('autoprefixer')]) + .process(result.css.toString(), { + from: cssBaseName, + to: cssBaseName, + map: { + prev: result.map.toString() + } + }) + .then((postCssResult) => { + return Promise.all([ + fsp.writeFile(path.join(outDirectoryPath, cssBaseName), postCssResult.css), + fsp.writeFile(path.join(outDirectoryPath, cssMapBaseName), JSON.stringify(postCssResult.map)) + ]).then(() => postCssResult) + }) + .then((postCssResult) => { + return postcss([require('cssnano')]) + .process(postCssResult.css, { + from: cssBaseName, + to: cssMinBaseName, + map: { + prev: JSON.stringify(postCssResult.map) + } + }); + }) + .then((postCssResult) => { + return Promise.all([ + fsp.writeFile(path.join(outDirectoryPath, cssMinBaseName), postCssResult.css), + fsp.writeFile(path.join(outDirectoryPath, cssMinMapBaseName), JSON.stringify(postCssResult.map)) + ]).then(() => postCssResult) + }); + }); +} + +module.exports = compileSass; diff --git a/tooling/node/styles-watch.js b/tooling/node/styles-watch.js new file mode 100755 index 00000000..f74ed8c8 --- /dev/null +++ b/tooling/node/styles-watch.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +const chokidar = require('chokidar'); +const compileSass = require('./compile-sass'); +const debounce = require('debounce'); + +const compileStyles = debounce(() => { + console.log(`Compiling styles.`); + compileSass('src/styles/chartist.scss', 'dist'); +}, 200); + +chokidar.watch('./src/**/*.scss') + .on('all', (event, path) => { + console.log(`Changes on path ${path}`); + compileStyles(); + }); diff --git a/tooling/node/styles.js b/tooling/node/styles.js new file mode 100755 index 00000000..fce1010a --- /dev/null +++ b/tooling/node/styles.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('./compile-sass')(process.argv[2], process.argv[3]); diff --git a/tooling/system-loaders/version-loader-plugin.js b/tooling/system-loaders/version-loader-plugin.js new file mode 100644 index 00000000..884fa294 --- /dev/null +++ b/tooling/system-loaders/version-loader-plugin.js @@ -0,0 +1,3 @@ +export function translate(load) { + return `export const version = '${JSON.parse(load.source).version}'`; +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..2c197b35 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4118 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@~1.3.3, accepts@1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +accepts@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.1.4.tgz#d71c96f7d41d0feda2c38cd14e8a27c04158df4a" + dependencies: + mime-types "~2.0.4" + negotiator "0.4.9" + +after@0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +amdefine@>=0.0.4: + version "1.0.0" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.0.tgz#fd17474700cb5cc9c2b709f0be9d23ce3c198c33" + +ansi-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-index@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + dependencies: + debug "^2.2.0" + es6-symbol "^3.0.2" + +array-slice@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arraybuffer.slice@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +asn1@0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + +assert-plus@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +async-each-series@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/async-each-series/-/async-each-series-0.1.1.tgz#7617c1917401fd8ca4a28aadce3dbae98afeb432" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + +async@^2.0.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.2.tgz#612a4ab45ef42a70cde806bad86ee6db047e8385" + dependencies: + lodash "^4.14.0" + +async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +async@0.1.15: + version "0.1.15" + resolved "https://registry.yarnpkg.com/async/-/async-0.1.15.tgz#2180eaca2cf2a6ca5280d41c0585bec9b3e49bd3" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +autoprefixer, autoprefixer@^6.3.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.5.1.tgz#ae759a5221e709f3da17c2d656230e67c43cbb75" + dependencies: + browserslist "~1.4.0" + caniuse-db "^1.0.30000554" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.4" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-code-frame@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^2.0.0" + +babel-core@^6.16.0, babel-core@^6.9.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.17.0.tgz#6c4576447df479e241e58c807e4bc7da4db7f425" + dependencies: + babel-code-frame "^6.16.0" + babel-generator "^6.17.0" + babel-helpers "^6.16.0" + babel-messages "^6.8.0" + babel-register "^6.16.0" + babel-runtime "^6.9.1" + babel-template "^6.16.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.4.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-exists "^1.0.0" + path-is-absolute "^1.0.0" + private "^0.1.6" + shebang-regex "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + +babel-generator@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.17.0.tgz#b894e3808beef7800f2550635bfe024b6226cf33" + dependencies: + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.16.0" + detect-indent "^3.0.1" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-hoist-variables@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.8.0.tgz#8b0766dc026ea9ea423bc2b34e665a4da7373aaf" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-helpers@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3" + dependencies: + babel-runtime "^6.0.0" + babel-template "^6.16.0" + +babel-messages@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-cjs-system-require@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-cjs-system-require/-/babel-plugin-transform-cjs-system-require-0.1.1.tgz#ffef26d31bc270e82bdbbd437db2777e85162a29" + +babel-plugin-transform-cjs-system-wrapper@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-cjs-system-wrapper/-/babel-plugin-transform-cjs-system-wrapper-0.2.1.tgz#e855078877b56d4d1b92b9f91b37f599db0200e3" + dependencies: + babel-plugin-transform-cjs-system-require "^0.1.1" + babel-template "^6.9.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.6.5: + version "6.14.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.14.0.tgz#c519b5c73e32388e679c9b1edf41b2fc23dc3303" + dependencies: + babel-helper-hoist-variables "^6.8.0" + babel-runtime "^6.11.6" + babel-template "^6.14.0" + +babel-plugin-transform-global-system-wrapper@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-global-system-wrapper/-/babel-plugin-transform-global-system-wrapper-0.0.1.tgz#afb469cec0e04689b9fe7e8b1fd280fc94a6d8f2" + dependencies: + babel-template "^6.9.0" + +babel-plugin-transform-system-register@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-system-register/-/babel-plugin-transform-system-register-0.0.1.tgz#9dff40390c2763ac518f0b2ad7c5ea4f65a5be25" + +babel-register@^6.16.0: + version "6.16.3" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.16.3.tgz#7b0c0ca7bfdeb9188ba4c27e5fcb7599a497c624" + dependencies: + babel-core "^6.16.0" + babel-runtime "^6.11.6" + core-js "^2.4.0" + home-or-tmp "^1.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + path-exists "^1.0.0" + source-map-support "^0.4.2" + +babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.9.0, babel-runtime@^6.9.1: + version "6.11.6" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-template@^6.14.0, babel-template@^6.16.0, babel-template@^6.9.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" + dependencies: + babel-runtime "^6.9.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.16.0.tgz#fba85ae1fd4d107de9ce003149cc57f53bef0c4f" + dependencies: + babel-code-frame "^6.16.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.16.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^8.3.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.16.0, babel-types@^6.8.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.16.0.tgz#71cca1dbe5337766225c5c193071e8ebcbcffcfe" + dependencies: + babel-runtime "^6.9.1" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.13.0.tgz#58ed40dd2a8120612be5f318c2c0bedbebde4a0b" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + +balanced-match@^0.4.1, balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +balanced-match@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a" + +base64-arraybuffer@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz#474df4a9f2da24e05df3158c3b1db3c3cd46a154" + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + +base64id@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" + +batch@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +benchmark@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-1.0.0.tgz#2f1e2fa4c359f11122aa183082218e957e390c73" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + +binary-extensions@^1.0.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.7.0.tgz#6c1610db163abfb34edfe42fa423343a1e01185d" + +bl@^1.0.0, bl@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" + dependencies: + readable-stream "~2.0.5" + +bl@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" + dependencies: + readable-stream "~2.0.5" + +blob@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.0.5, bluebird@^3.3.0, bluebird@^3.3.4: + version "3.4.6" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.6.tgz#01da8d821d87813d158967e743d5fe6c62cf8c0f" + +body-parser@^1.12.4: + version "1.15.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67" + dependencies: + bytes "2.4.0" + content-type "~1.0.2" + debug "~2.2.0" + depd "~1.1.0" + http-errors "~1.5.0" + iconv-lite "0.4.13" + on-finished "~2.3.0" + qs "6.2.0" + raw-body "~2.1.7" + type-is "~1.6.13" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^0.1.2: + version "0.1.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-0.1.5.tgz#c085711085291d8b75fdd74eab0f8597280711e6" + dependencies: + expand-range "^0.1.0" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browser-sync: + version "2.17.5" + resolved "https://registry.yarnpkg.com/browser-sync/-/browser-sync-2.17.5.tgz#8e0a9ddfc2e162e7aada085f76181c57b6dbdf7a" + dependencies: + browser-sync-client "^2.3.3" + browser-sync-ui "0.6.1" + bs-recipes "1.2.3" + chokidar "1.6.0" + connect "3.5.0" + dev-ip "^1.0.1" + easy-extender "2.3.2" + eazy-logger "3.0.2" + emitter-steward "^1.0.0" + fs-extra "0.30.0" + http-proxy "1.15.1" + immutable "3.8.1" + localtunnel "1.8.1" + micromatch "2.3.11" + opn "4.0.2" + portscanner "^1.0.0" + qs "6.2.1" + resp-modifier "6.0.2" + rx "4.1.0" + serve-index "1.8.0" + serve-static "1.11.1" + server-destroy "1.0.1" + socket.io "1.5.0" + ua-parser-js "0.7.10" + yargs "6.0.0" + +browser-sync-client@^2.3.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.4.3.tgz#e965033e0c83e5f06caacb516755b694836cea4f" + dependencies: + etag "^1.7.0" + fresh "^0.3.0" + +browser-sync-ui@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/browser-sync-ui/-/browser-sync-ui-0.6.1.tgz#d8b98ea3b755632287350a37ee2eaaacabea28d2" + dependencies: + async-each-series "0.1.1" + connect-history-api-fallback "^1.1.0" + immutable "^3.7.6" + server-destroy "1.0.1" + stream-throttle "^0.1.3" + weinre "^2.0.0-pre-I0Z7U9OV" + +browserslist@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.4.0.tgz#9cfdcf5384d9158f5b70da2aa00b30e8ff019049" + dependencies: + caniuse-db "^1.0.30000539" + +bs-recipes@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bs-recipes/-/bs-recipes-1.2.3.tgz#0e4d17bb1cff92ef6c36608b8487d9a07571ac54" + +bser@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" + dependencies: + node-int64 "^0.4.0" + +buffer-peek-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-peek-stream/-/buffer-peek-stream-1.0.1.tgz#53b47570a1347787c5bad4ca2ca3021f9d8b3cfd" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^1.0.2, camelcase@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +caniuse-db@^1.0.30000539, caniuse-db@^1.0.30000554: + version "1.0.30000564" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000564.tgz#840a4d9e5c15dc9c6df84d7051f28e30514cc00b" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar, chokidar@^1.4.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chokidar@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.0.tgz#90c32ad4802901d7713de532dc284e96a63ad058" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +clap@^1.0.9: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.1.tgz#a8a93e0bfb7581ac199c4f001a5525a724ce696d" + dependencies: + chalk "^1.1.3" + +cli-color@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-0.3.3.tgz#12d5bdd158ff8a0b0db401198913c03df069f6f5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.6" + memoizee "~0.3.8" + timers-ext "0.1" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.0.3, cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +coa@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.0.1.tgz#1104cd34f9b5b45d3eba88f1babc1924e1ce35fb" + dependencies: + number-is-nan "^1.0.0" + +color-convert@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.5.0.tgz#7a2b4efb4488df85bca6443cb038b7100fbe7de1" + +color-name@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color@^0.11.0: + version "0.11.3" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.3.tgz#4bad1d0d52499dd00dbd6f0868442467e49394e6" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@^1.1.0, colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +combine-lists@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6" + dependencies: + lodash "^4.5.0" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.2.0, commander@^2.9.0, commander@2.9.x: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + +component-emitter@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.0.tgz#ccd113a86388d06482d03de3fc7df98526ba8efe" + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +connect-history-api-fallback@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" + +connect@^3.3.5, connect@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.5.0.tgz#b357525a0b4c1f50599cd983e1d9efeea9677198" + dependencies: + debug "~2.2.0" + finalhandler "0.5.0" + parseurl "~1.3.1" + utils-merge "1.0.0" + +connect@1.x: + version "1.9.2" + resolved "https://registry.yarnpkg.com/connect/-/connect-1.9.2.tgz#42880a22e9438ae59a8add74e437f58ae8e52807" + dependencies: + formidable "1.0.x" + mime ">= 0.0.1" + qs ">= 0.4.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +core-js@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-js@^2.2.0, core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +css-color-names@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +cssnano: + version "3.7.7" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.7.7.tgz#27fac611380c6a49d6f722c0537e5a988a785010" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +csso@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.2.1.tgz#51fbb5347e50e81e6ed51668a48490ae6fe2afe2" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +ctype@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + +d@^0.1.1, d@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + dependencies: + es5-ext "~0.10.2" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +dashdash@^1.12.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.0.tgz#29e486c5418bf0f356034a993d51686a33e84141" + dependencies: + assert-plus "^1.0.0" + +data-uri-to-buffer@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-0.0.4.tgz#46e13ab9da8e309745c8d01ce547213ebdb2fe3f" + +date-now@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-1.0.1.tgz#bb7d086438debe4182a485fb3df3fbfb99d6153c" + +debounce: + version "1.0.0" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.0.0.tgz#0948af513d2e4ce407916f8506a423d3f9cf72d8" + dependencies: + date-now "1.0.1" + +debug@^2.1.1, debug@^2.2.0, debug@~2.2.0, debug@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-file@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + dependencies: + fs-exists-sync "^0.1.0" + +detect-indent@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + dependencies: + get-stdin "^4.0.1" + minimist "^1.1.0" + repeating "^1.1.0" + +dev-ip@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0" + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + +dom-serialize@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +easy-extender@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/easy-extender/-/easy-extender-2.3.2.tgz#3d3248febe2b159607316d8f9cf491c16648221d" + dependencies: + lodash "^3.10.1" + +eazy-logger@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/eazy-logger/-/eazy-logger-3.0.2.tgz#a325aa5e53d13a2225889b2ac4113b2b9636f4fc" + dependencies: + tfunk "^3.0.1" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +emitter-steward@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/emitter-steward/-/emitter-steward-1.0.0.tgz#f3411ade9758a7565df848b2da0cbbd1b46cbd64" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.1.0.tgz#e9353258baa9108965efc41cb0ef8ade2f3cfb07" + dependencies: + once "~1.3.0" + +engine.io-client@1.6.9: + version "1.6.9" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.6.9.tgz#1d6ad48048a5083c95096943b29d36efdb212401" + dependencies: + component-emitter "1.1.2" + component-inherit "0.0.3" + debug "2.2.0" + engine.io-parser "1.2.4" + has-cors "1.1.0" + indexof "0.0.1" + parsejson "0.0.1" + parseqs "0.0.2" + parseuri "0.0.4" + ws "1.0.1" + xmlhttprequest-ssl "1.5.1" + yeast "0.1.2" + +engine.io-client@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.7.0.tgz#0bb81d3563ab7afb668f1e1b400c9403b03006ee" + dependencies: + component-emitter "1.1.2" + component-inherit "0.0.3" + debug "2.2.0" + engine.io-parser "1.3.0" + has-cors "1.1.0" + indexof "0.0.1" + parsejson "0.0.1" + parseqs "0.0.2" + parseuri "0.0.4" + ws "1.1.1" + xmlhttprequest-ssl "1.5.1" + yeast "0.1.2" + +engine.io-parser@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.2.4.tgz#e0897b0bf14e792d4cd2a5950553919c56948c42" + dependencies: + after "0.8.1" + arraybuffer.slice "0.0.6" + base64-arraybuffer "0.1.2" + blob "0.0.4" + has-binary "0.1.6" + utf8 "2.1.0" + +engine.io-parser@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.0.tgz#61a35c7f3a3ccd1b179e4f52257a7a8cfacaeb21" + dependencies: + after "0.8.1" + arraybuffer.slice "0.0.6" + base64-arraybuffer "0.1.5" + blob "0.0.4" + has-binary "0.1.6" + wtf-8 "1.0.0" + +engine.io@1.6.10: + version "1.6.10" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.6.10.tgz#f87d84e1bd21d1a2ec7f8deef0c62054acdfb27a" + dependencies: + accepts "1.1.4" + base64id "0.1.0" + debug "2.2.0" + engine.io-parser "1.2.4" + ws "1.0.1" + +engine.io@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.7.0.tgz#a417857af4995d9bbdf8a0e03a87e473ebe64fbe" + dependencies: + accepts "1.3.3" + base64id "0.1.0" + debug "2.2.0" + engine.io-parser "1.3.0" + ws "1.1.1" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + +err-code@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.1.tgz#739d71b6851f24d050ea18c79a5b722420771d59" + +error-ex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + dependencies: + is-arrayish "^0.2.1" + +es5-ext@^0.10.12, es5-ext@^0.10.7, es5-ext@^0.10.9, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.5, es5-ext@~0.10.6, es5-ext@~0.10.7: + version "0.10.12" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-0.1.3.tgz#d6f58b8c4fc413c249b4baa19768f8e4d7c8944e" + dependencies: + d "~0.1.1" + es5-ext "~0.10.5" + es6-symbol "~2.0.1" + +es6-iterator@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + dependencies: + d "^0.1.1" + es5-ext "^0.10.7" + es6-symbol "3" + +es6-promise@~4.0.3: + version "4.0.5" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" + +es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + +es6-symbol@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-2.0.1.tgz#761b5c67cfd4f1d18afb234f691d678682cb3bf3" + dependencies: + d "~0.1.1" + es5-ext "~0.10.5" + +es6-template-strings@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-template-strings/-/es6-template-strings-2.0.1.tgz#b166c6a62562f478bb7775f6ca96103a599b4b2c" + dependencies: + es5-ext "^0.10.12" + esniff "^1.1" + +es6-weak-map@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-0.1.4.tgz#706cef9e99aa236ba7766c239c8b9e286ea7d228" + dependencies: + d "~0.1.1" + es5-ext "~0.10.6" + es6-iterator "~0.1.3" + es6-symbol "~2.0.1" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +esniff@^1.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/esniff/-/esniff-1.1.0.tgz#c66849229f91464dede2e0d40201ed6abf65f2ac" + dependencies: + d "1" + es5-ext "^0.10.12" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@^1.7.0, etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-emitter@~0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.7" + +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + +exec-sh@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + dependencies: + merge "^1.1.3" + +expand-braces@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" + dependencies: + array-slice "^0.2.3" + array-unique "^0.2.1" + braces "^0.1.2" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-0.1.1.tgz#4cb8eda0993ca56fa4f41fc42f3cbb4ccadff044" + dependencies: + is-number "^0.1.1" + repeat-string "^0.2.2" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expand-tilde@^1.2.0, expand-tilde@^1.2.1, expand-tilde@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + dependencies: + os-homedir "^1.0.1" + +express@2.5.x: + version "2.5.11" + resolved "https://registry.yarnpkg.com/express/-/express-2.5.11.tgz#4ce8ea1f3635e69e49f0ebb497b6a4b0a51ce6f0" + dependencies: + connect "1.x" + mime "1.2.4" + mkdirp "0.3.0" + qs "0.4.x" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extract-zip@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" + dependencies: + concat-stream "1.5.0" + debug "0.7.4" + mkdirp "0.5.0" + yauzl "2.4.1" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fb-watchman@^1.8.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.0.tgz#6f268f1f347a6b3c875d1e89da7e1ed79adfc0ec" + dependencies: + bser "^1.0.2" + +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + statuses "~1.3.0" + unpipe "~1.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +findup-sync@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + dependencies: + detect-file "^0.1.0" + is-glob "^2.0.1" + micromatch "^2.3.7" + resolve-dir "^0.1.0" + +fined@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fined/-/fined-1.0.2.tgz#5b28424b760d7598960b7ef8480dff8ad3660e97" + dependencies: + expand-tilde "^1.2.1" + lodash.assignwith "^4.0.7" + lodash.isempty "^4.2.1" + lodash.isplainobject "^4.0.4" + lodash.isstring "^4.0.1" + lodash.pick "^4.2.1" + parse-filepath "^1.0.1" + +flagged-respawn@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~1.0.0-rc3, form-data@~1.0.0-rc4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + dependencies: + async "^2.0.1" + combined-stream "^1.0.5" + mime-types "^2.1.11" + +form-data@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.11" + +formidable@1.0.x: + version "1.0.17" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.0.17.tgz#ef5491490f9433b705faa77249c99029ae348559" + +fresh@^0.3.0, fresh@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + +fs-extra@^0.26.5: + version "0.26.7" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@~0.30.0, fs-extra@0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-promise: + version "0.5.0" + resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-0.5.0.tgz#4347d6bf624655a7061a4319213c393276ad3ef3" + dependencies: + any-promise "^1.0.0" + fs-extra "^0.26.5" + mz "^2.3.1" + thenify-all "^1.6.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.14" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.14.tgz#558e8cc38643d8ef40fe45158486d0d25758eee4" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +gauge@~2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-color "^0.1.7" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" + dependencies: + globule "^1.0.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^6.0.1: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@~3.2: + version "3.2.11" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" + dependencies: + inherits "2" + minimatch "0.3" + +glob@~7.0.3: + version "7.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@5.0.x: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + dependencies: + global-prefix "^0.1.4" + is-windows "^0.2.0" + +global-prefix@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.4.tgz#05158db1cde2dd491b455e290eb3ab8bfc45c6e1" + dependencies: + ini "^1.3.4" + is-windows "^0.2.0" + osenv "^0.1.3" + which "^1.2.10" + +globals@^8.3.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-8.18.0.tgz#93d4a62bdcac38cfafafc47d6b034768cb0ffcb4" + +globule@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.0.0.tgz#f22aebaacce02be492453e979c3ae9b6983f1c6c" + dependencies: + glob "~7.0.3" + lodash "~4.9.0" + minimatch "~3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6: + version "4.1.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.9.tgz#baacba37d19d11f9d146d3578bc99958c3787e29" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +har-validator@~2.0.2, har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-binary@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + dependencies: + isarray "0.0.1" + +has-binary@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + dependencies: + isarray "0.0.1" + +has-color@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hasha@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" + dependencies: + is-stream "^1.0.1" + pinkie-promise "^2.0.0" + +hawk@~3.1.0, hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + dependencies: + os-tmpdir "^1.0.1" + user-home "^1.1.1" + +hosted-git-info@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +http-errors@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.0.tgz#b1cb3d8260fd8e2386cad3189045943372d48211" + dependencies: + inherits "2.0.1" + setprototypeof "1.0.1" + statuses ">= 1.3.0 < 2" + +http-proxy@^1.13.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.15.2.tgz#642fdcaffe52d3448d2bda3b0079e9409064da31" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + +http-proxy@1.15.1: + version "1.15.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.15.1.tgz#91a6088172e79bc0e821d5eb04ce702f32446393" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + +http-signature@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6" + dependencies: + asn1 "0.1.11" + assert-plus "^0.1.5" + ctype "0.5.3" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +immutable@^3.7.6, immutable@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2" + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +interpolate: + version "0.1.0" + resolved "https://registry.yarnpkg.com/interpolate/-/interpolate-0.1.0.tgz#b60177a4ba941fb3724c821905d99aade13d1df9" + +invariant@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.1.tgz#b097010547668c7e337028ebe816ebe36c8a8d54" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +is-absolute-url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.0.0.tgz#9c4b20b0e5c0cbef9a479a367ede6f991679f359" + +is-absolute@^0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb" + dependencies: + is-relative "^0.2.1" + is-windows "^0.2.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-relative@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5" + dependencies: + is-unc-path "^0.1.1" + +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.0.1.tgz#f93ab3bf1d6bbca30e9753cd3485b1300eebc013" + dependencies: + html-comment-regex "^1.1.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-unc-path@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.1.tgz#ab2533d77ad733561124c3dc0f5cd8b90054c86b" + dependencies: + unc-path-regex "^0.1.0" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + +is@~0.2.6: + version "0.2.7" + resolved "https://registry.yarnpkg.com/is/-/is-0.2.7.tgz#3b34a2c48f359972f35042849193ae7264b63562" + +isarray@~1.0.0, isarray@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isbinaryfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.1.tgz#6e99573675372e841a0520c036b41513d783e79e" + +isexe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jasmine-core: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.5.2.tgz#6f61bd79061e27f43e6f9355e44b3c6cab6ff297" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-base64@^2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" + +js-tokens@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.3.tgz#14e56eb68c8f1a92c43d59f5014ec29dc20f2ae1" + +js-tokens@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" + +js-yaml@~3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.2.6.tgz#f6efc93c06a04de9aec53053df2559bb19e2038b" + +json3@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonpointer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" + +jspm-github@^0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/jspm-github/-/jspm-github-0.14.11.tgz#5093b3a79289d63ff6e3982f3b527878ac808d5c" + dependencies: + bluebird "^3.0.5" + expand-tilde "^1.2.0" + graceful-fs "^4.1.3" + mkdirp "^0.5.1" + netrc "^0.1.3" + request "^2.74.0" + rimraf "^2.5.4" + semver "^5.0.1" + tar-fs "^1.13.0" + which "^1.0.9" + +jspm-npm@^0.29.5: + version "0.29.7" + resolved "https://registry.yarnpkg.com/jspm-npm/-/jspm-npm-0.29.7.tgz#029159c3fe210d20f6965821697082e9a2be40ce" + dependencies: + bluebird "^3.0.5" + buffer-peek-stream "^1.0.1" + graceful-fs "^4.1.3" + mkdirp "^0.5.1" + readdirp "^2.0.0" + request "^2.58.0" + rmdir "^1.1.0" + semver "^5.0.1" + systemjs-builder "^0.15.20" + tar-fs "^1.13.0" + traceur "0.0.105" + which "^1.1.1" + +jspm-registry@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/jspm-registry/-/jspm-registry-0.4.1.tgz#2a30c419906ad71d4da692d1532009dd201c5b14" + dependencies: + graceful-fs "^4.1.3" + rimraf "^2.3.2" + rsvp "^3.0.18" + semver "^4.3.3" + +jspm@beta: + version "0.17.0-beta.29" + resolved "https://registry.yarnpkg.com/jspm/-/jspm-0.17.0-beta.29.tgz#b75f13db7734ba492285409bb57499fb6956e7b2" + dependencies: + bluebird "^3.0.5" + chalk "^1.1.1" + core-js "^1.2.6" + glob "^6.0.1" + graceful-fs "^4.1.2" + jspm-github "^0.14.11" + jspm-npm "^0.29.5" + jspm-registry "^0.4.1" + liftoff "^2.2.0" + minimatch "^3.0.0" + mkdirp "~0.5.1" + ncp "^2.0.0" + proper-lockfile "^1.1.2" + request "^2.67.0" + rimraf "^2.4.4" + sane "^1.3.3" + semver "^5.1.0" + systemjs "0.19.39" + systemjs-builder "0.15.32" + traceur "0.0.105" + uglify-js "^2.6.1" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +karma: + version "1.3.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-1.3.0.tgz#b2b94e8f499fadd0069d54f9aef4a4d48ec5cc1f" + dependencies: + bluebird "^3.3.0" + body-parser "^1.12.4" + chokidar "^1.4.1" + colors "^1.1.0" + combine-lists "^1.0.0" + connect "^3.3.5" + core-js "^2.2.0" + di "^0.0.1" + dom-serialize "^2.2.0" + expand-braces "^0.1.1" + glob "^7.0.3" + graceful-fs "^4.1.2" + http-proxy "^1.13.0" + isbinaryfile "^3.0.0" + lodash "^3.8.0" + log4js "^0.6.31" + mime "^1.3.4" + minimatch "^3.0.0" + optimist "^0.6.1" + qjobs "^1.1.4" + range-parser "^1.2.0" + rimraf "^2.3.3" + socket.io "1.4.7" + source-map "^0.5.3" + tmp "0.0.28" + useragent "^2.1.9" + +karma-jasmine: + version "1.0.2" + resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.0.2.tgz#c0b3ab327bf207db60e17fa27db37cfdef5d8e6c" + +karma-jspm: + version "2.2.0" + resolved "https://registry.yarnpkg.com/karma-jspm/-/karma-jspm-2.2.0.tgz#ce8eaa730896e0b95ab3645b9b8ec5b3a1c419a7" + dependencies: + glob "~3.2" + +karma-nyan-reporter: + version "0.2.4" + resolved "https://registry.yarnpkg.com/karma-nyan-reporter/-/karma-nyan-reporter-0.2.4.tgz#361bc4135002cbe504a36e38f3506e866d6a852c" + dependencies: + cli-color "^0.3.2" + +karma-phantomjs-launcher: + version "1.0.2" + resolved "https://registry.yarnpkg.com/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.2.tgz#19e1041498fd75563ed86730a22c1fe579fa8fb1" + dependencies: + lodash "^4.0.1" + phantomjs-prebuilt "^2.1.7" + +kew@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + +kind-of@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" + dependencies: + is-buffer "^1.0.2" + +klaw@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.0.tgz#8857bfbc1d824badf13d3d0241d8bbe46fb12f73" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +liftoff@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385" + dependencies: + extend "^3.0.0" + findup-sync "^0.4.2" + fined "^1.0.1" + flagged-respawn "^0.3.2" + lodash.isplainobject "^4.0.4" + lodash.isstring "^4.0.1" + lodash.mapvalues "^4.4.0" + rechoir "^0.6.2" + resolve "^1.1.7" + +limiter@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.0.tgz#6e2bd12ca3fcdaa11f224e2e53c896df3f08d913" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +localtunnel@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.8.1.tgz#d51b2bb7a7066afb05b57fc9db844015098f2e17" + dependencies: + debug "2.2.0" + openurl "1.1.0" + request "2.65.0" + yargs "3.29.0" + +lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.assignwith@^4.0.7: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb" + +lodash.clonedeep@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.indexof@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/lodash.indexof/-/lodash.indexof-4.0.5.tgz#53714adc2cddd6ed87638f893aa9b6c24e31ef3c" + +lodash.isempty@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" + +lodash.isplainobject@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + +lodash.mapvalues@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + +lodash@^3.10.1, lodash@^3.8.0: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + +lodash@^4.0.0, lodash@^4.0.1, lodash@^4.14.0, lodash@^4.2.0, lodash@^4.5.0: + version "4.16.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.4.tgz#01ce306b9bad1319f2a5528674f88297aeb70127" + +lodash@~4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.9.0.tgz#4c20d742f03ce85dc700e0dd7ab9bcab85e6fc14" + +log4js@^0.6.31: + version "0.6.38" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-0.6.38.tgz#2c494116695d6fb25480943d3fc872e662a522fd" + dependencies: + readable-stream "~1.0.2" + semver "~4.3.3" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.2.0.tgz#69a65aad3de542cf4ee0f4fe74e8e33c709ccb0f" + dependencies: + js-tokens "^1.0.1" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lru-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.1.tgz#1343955edaf2e37d9b9e7ee7241e27c4b9fb72be" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +lru-cache@2.2.x: + version "2.2.4" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d" + +lru-queue@0.1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + dependencies: + es5-ext "~0.10.2" + +macaddress@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +math-expression-evaluator@^1.2.14: + version "1.2.14" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.14.tgz#39511771ed9602405fba9affff17eb4d2a3843ab" + dependencies: + lodash.indexof "^4.0.5" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +memoizee@~0.3.8: + version "0.3.10" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.3.10.tgz#4eca0d8aed39ec9d017f4c5c2f2f6432f42e5c8f" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-weak-map "~0.1.4" + event-emitter "~0.3.4" + lru-queue "0.1" + next-tick "~0.2.2" + timers-ext "0.1" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + +micromatch@^2.1.5, micromatch@^2.3.7, micromatch@2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.12.0.tgz#3d0c63180f458eb10d325aaa37d7c58ae312e9d7" + +mime-db@~1.24.0: + version "1.24.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.24.0.tgz#e2d13f939f0016c6e4e9ad25a8652f126c467f0c" + +mime-types@^2.1.11, mime-types@~2.1.11, mime-types@~2.1.7: + version "2.1.12" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.12.tgz#152ba256777020dd4663f54c2e7bc26381e71729" + dependencies: + mime-db "~1.24.0" + +mime-types@~2.0.4: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.0.14.tgz#310e159db23e077f8bb22b748dabfa4957140aa6" + dependencies: + mime-db "~1.12.0" + +mime@^1.3.4, "mime@>= 0.0.1", mime@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +mime@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.4.tgz#11b5fdaf29c2509255176b80ad520294f5de92b7" + +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@~3.0.0, "minimatch@2 || 3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimatch@0.3: + version "0.3.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +mkdirp@^0.5.0, mkdirp@^0.5.1, "mkdirp@>=0.5 0", mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +mz@^2.3.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.4.0.tgz#987ba9624d89395388c37cb4741e2caf4dd13b1a" + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@^2.3.0, nan@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" + +ncp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + +negotiator@0.4.9: + version "0.4.9" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.4.9.tgz#92e46b6db53c7e421ed64a2bc94f08be7630df3f" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +netrc@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/netrc/-/netrc-0.1.4.tgz#6be94fcaca8d77ade0a9670dc460914c94472444" + +next-tick@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-0.2.2.tgz#75da4a927ee5887e39065880065b7336413b310d" + +node-gyp@^3.3.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3" + osenv "0" + path-array "^1.0.0" + request "2" + rimraf "2" + semver "2.x || 3.x || 4 || 5" + tar "^2.0.0" + which "1" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + +node-pre-gyp@^0.6.29: + version "0.6.30" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.30.tgz#64d3073a6f573003717ccfe30c89023297babba1" + dependencies: + mkdirp "~0.5.0" + nopt "~3.0.1" + npmlog "4.x" + rc "~1.1.0" + request "2.x" + rimraf "~2.5.0" + semver "~5.3.0" + tar "~2.2.0" + tar-pack "~3.1.0" + +node-sass: + version "3.10.1" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-3.10.1.tgz#c535b2e1a5439240591e06d7308cb663820d616c" + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.3.2" + node-gyp "^3.3.1" + npmlog "^4.0.0" + request "^2.61.0" + sass-graph "^2.1.1" + +node-uuid@~1.4.3, node-uuid@~1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + +node.extend@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.0.8.tgz#bab04379f7383f4587990c9df07b6a7f65db772b" + dependencies: + is "~0.2.6" + object-keys "~0.4.0" + +node.flow@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/node.flow/-/node.flow-1.2.3.tgz#e1c44a82aeca8d78b458a77fb3dc642f2eba2649" + dependencies: + node.extend "1.0.8" + +nopt@~3.0.1, "nopt@2 || 3", nopt@3.0.x: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^1.4.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.7.0.tgz#d82452d98d38821cffddab4d77a5f8d20ce66db0" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +npmlog@^4.0.0, npmlog@4.x: + version "4.0.0" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.0.tgz#e094503961c70c1774eb76692080e8d578a9f88f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.6.0" + set-blocking "~2.0.0" + +"npmlog@0 || 1 || 2 || 3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.6.0" + set-blocking "~2.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.0, oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + +object-path@^0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.9.2.tgz#0fd9a74fc5fad1ae3968b586bda5c632bd6c05a5" + +object.omit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.0.tgz#868597333d54e60662940bb458605dd6ae12fe94" + dependencies: + for-own "^0.1.3" + is-extendable "^0.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +openurl@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.0.tgz#e2f2189d999c04823201f083f0f1a7cd8903187a" + +opn@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +options@>=0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.3, osenv@0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.3.tgz#83cf05c6d6458fc4d5ac6362ea325d92f2754217" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +parse-filepath@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73" + dependencies: + is-absolute "^0.2.3" + map-cache "^0.2.0" + path-root "^0.1.1" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parsejson@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.1.tgz#9b10c6c0d825ab589e685153826de0a3ba278bcc" + dependencies: + better-assert "~1.0.0" + +parseqs@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.2.tgz#9dfe70b2cddac388bde4f35b1f240fa58adbe6c7" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.4.tgz#806582a39887e1ea18dd5e2fe0e01902268e9350" + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-array@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + dependencies: + array-index "^1.0.0" + +path-exists@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + dependencies: + path-root-regex "^0.1.0" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + +phantomjs-prebuilt@^2.1.7: + version "2.1.13" + resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.13.tgz#66556ad9e965d893ca5a7dc9e763df7e8697f76d" + dependencies: + es6-promise "~4.0.3" + extract-zip "~1.5.0" + fs-extra "~0.30.0" + hasha "~2.2.0" + kew "~0.7.0" + progress "~1.1.8" + request "~2.74.0" + request-progress "~2.0.1" + which "~1.2.10" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +portscanner@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/portscanner/-/portscanner-1.0.0.tgz#3b5cfe393828b5160abc600e6270ebc2f1590558" + dependencies: + async "0.1.15" + +postcss, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.4: + version "5.2.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.5.tgz#ec428c27dffc7fac65961340a9b022fa4af5f056" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.1.2" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-colormin@^2.1.8: + version "2.2.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.1.tgz#dc5421b6ae6f779ef6bfd47352b94abe59d0316b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-convert-values@^2.3.4: + version "2.4.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.4.1.tgz#45dce4d4e33b7d967b97a4d937f270ea98d2fe7a" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-duplicates@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.0.1.tgz#5fae3f1a71df3e19cffb37309d1a7dba56c4589c" + dependencies: + postcss "^5.0.4" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-unused@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.2.tgz#5d72f7d05d11de0a9589e001958067ccae1b4931" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" + dependencies: + postcss "^5.0.4" + uniqid "^4.0.0" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.1.tgz#ff59b5dec6d586ce2cea183138f55c5876fa9cdc" + dependencies: + postcss "^5.0.4" + +postcss-merge-rules@^2.0.3: + version "2.0.10" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.0.10.tgz#54b360be804e7e69a5c7222635247b92a3569e9b" + dependencies: + postcss "^5.0.4" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-gradients@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.4.tgz#47d4fef7efbcc64e541fae6115c9a3cc84d47006" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-params@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.0.5.tgz#82d602643b8616a61fb3634d7ede0289836d67f9" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.0.5.tgz#4e1f966fb49c95266804016ba9a3c6645bb601e0" + dependencies: + alphanum-sort "^1.0.2" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-normalize-charset@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.0.tgz#2fbd30e12248c442981d31ea2484d46fd0628970" + dependencies: + postcss "^5.0.5" + +postcss-normalize-url@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.7.tgz#6bd90d0a4bc5a1df22c26ea65c53257dc3829f4e" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-ordered-values@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.2.tgz#be8b511741fab2dac8e614a2302e9d10267b0771" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-reduce-idents@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.3.1.tgz#024e8e219f52773313408573db9645ba62d2d2fe" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.0.tgz#8f739b938289ef2e48936d7101783e4741ca9bbb" + dependencies: + postcss "^5.0.4" + +postcss-reduce-transforms@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.3.tgz#fc193e435a973c10f9801c74700a830f79643343" + dependencies: + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-selector-parser@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.1.tgz#fdbf696103b12b0a64060e5610507f410491f7c8" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.5" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.5.tgz#46fc0363f01bab6a36a9abb01c229fcc45363094" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.1.1.tgz#ea3fbe656c9738aa8729e2ee96ec2a46089b720f" + dependencies: + postcss "^5.0.4" + uniqs "^2.0.0" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +progress@~1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +proper-lockfile@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-1.2.0.tgz#ceff5dd89d3e5f10fb75e1e8e76bc75801a59c34" + dependencies: + err-code "^1.0.0" + extend "^3.0.0" + graceful-fs "^4.1.2" + retry "^0.10.0" + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +pump@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.1.tgz#f1f1409fb9bd1085bbdb576b43b84ec4b5eadc1a" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +q@^1.1.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + +qjobs@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.1.5.tgz#659de9f2cf8dcc27a1481276f205377272382e73" + +"qs@>= 0.4.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +qs@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc" + +qs@~6.2.0, qs@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" + +qs@0.4.x: + version "0.4.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-0.4.2.tgz#3cac4c861e371a8c9c4770ac23cda8de639b8e5f" + +qs@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +query-string@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.2.3.tgz#9f27273d207a25a8ee4c7b8c74dcd45d556db822" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +randomatic@^1.1.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.5.tgz#5e9ef5f2d573c67bd2b8124ae90b5156e457840b" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +range-parser@^1.2.0, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@~2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" + +rc@~1.1.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~1.0.2: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.0.0, readable-stream@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.1.tgz#fa02e126e695824263cab91d3a5b0fdc1dd27a9a" + dependencies: + balanced-match "~0.1.0" + +regenerator-runtime@^0.9.5: + version "0.9.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.5.tgz#403d6d40a4bdff9c330dd9392dcbb2d9a8bba1fc" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae" + +repeat-string@^1.5.2: + version "1.5.4" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.5.4.tgz#64ec0c91e0f4b475f90d5b643651e3e6e5b6c2d5" + +repeating@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request-progress@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" + dependencies: + throttleit "^1.0.0" + +request@^2.58.0, request@^2.61.0, request@^2.67.0, request@^2.74.0, request@2, request@2.x: + version "2.75.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.1.2" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.0.0" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.1" + qs "~6.2.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + +request@~2.74.0: + version "2.74.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.1.2" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~1.0.0-rc4" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.1" + qs "~6.2.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + +request@2.65.0: + version "2.65.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.65.0.tgz#cc1a3bc72b96254734fc34296da322f9486ddeba" + dependencies: + aws-sign2 "~0.6.0" + bl "~1.0.0" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~1.0.0-rc3" + har-validator "~2.0.2" + hawk "~3.1.0" + http-signature "~0.11.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.3" + oauth-sign "~0.8.0" + qs "~5.2.0" + stringstream "~0.0.4" + tough-cookie "~2.2.0" + tunnel-agent "~0.4.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +requires-port@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-dir@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + dependencies: + expand-tilde "^1.2.2" + global-modules "^0.2.3" + +resolve@^1.1.6, resolve@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resp-modifier@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/resp-modifier/-/resp-modifier-6.0.2.tgz#b124de5c4fbafcba541f48ffa73970f4aa456b4f" + dependencies: + debug "^2.2.0" + minimatch "^3.0.2" + +retry@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.0.tgz#649e15ca408422d98318161935e7f7d652d435dd" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.3, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@~2.5.0, rimraf@~2.5.1, rimraf@2: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +rmdir@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/rmdir/-/rmdir-1.2.0.tgz#4fe0357cb06168c258e73e968093dc4e8a0f3253" + dependencies: + node.flow "1.2.3" + +rollup@^0.36.0: + version "0.36.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.36.3.tgz#c89ac479828924ff8f69c1d44541cb4ea2fc11fc" + dependencies: + source-map-support "^0.4.0" + +rsvp@^3.0.13, rsvp@^3.0.18: + version "3.3.3" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813" + +rx@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + +sane@^1.3.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sane/-/sane-1.4.1.tgz#88f763d74040f5f0c256b6163db399bf110ac715" + dependencies: + exec-sh "^0.2.0" + fb-watchman "^1.8.0" + minimatch "^3.0.2" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.10.0" + +sass-graph@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.1.2.tgz#965104be23e8103cb7e5f710df65935b317da57b" + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + yargs "^4.7.1" + +sax@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + +semver@^4.3.3, semver@~4.3.3: + version "4.3.6" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + +semver@^5.0.1, semver@^5.1.0, semver@~5.3.0, "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5": + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +send@0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.5.0" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.0" + +serve-index@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.8.0.tgz#7c5d96c13fb131101f93c1c5774f8516a1e78d3b" + dependencies: + accepts "~1.3.3" + batch "0.5.3" + debug "~2.2.0" + escape-html "~1.0.3" + http-errors "~1.5.0" + mime-types "~2.1.11" + parseurl "~1.3.1" + +serve-static@1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.14.1" + +server-destroy@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setprototypeof@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.1.tgz#52009b27888c4dc48f591949c0a8275834c1ca7e" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.1.tgz#5a4c884992b63a7acd9badb7894c3ee9cfccad81" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +socket.io-adapter@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.4.0.tgz#fb9f82ab1aa65290bf72c3657955b930a991a24f" + dependencies: + debug "2.2.0" + socket.io-parser "2.2.2" + +socket.io-client@1.4.6: + version "1.4.6" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.4.6.tgz#49b0ba537efd15b8297c84016e642e1c7c752c3d" + dependencies: + backo2 "1.0.2" + component-bind "1.0.0" + component-emitter "1.2.0" + debug "2.2.0" + engine.io-client "1.6.9" + has-binary "0.1.7" + indexof "0.0.1" + object-component "0.0.3" + parseuri "0.0.4" + socket.io-parser "2.2.6" + to-array "0.1.4" + +socket.io-client@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.5.0.tgz#08232d0adb5a665a7c24bd9796557a33f58f38ae" + dependencies: + backo2 "1.0.2" + component-bind "1.0.0" + component-emitter "1.2.0" + debug "2.2.0" + engine.io-client "1.7.0" + has-binary "0.1.7" + indexof "0.0.1" + object-component "0.0.3" + parseuri "0.0.4" + socket.io-parser "2.2.6" + to-array "0.1.4" + +socket.io-parser@2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.2.2.tgz#3d7af6b64497e956b7d9fe775f999716027f9417" + dependencies: + benchmark "1.0.0" + component-emitter "1.1.2" + debug "0.7.4" + isarray "0.0.1" + json3 "3.2.6" + +socket.io-parser@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.2.6.tgz#38dfd61df50dcf8ab1d9e2091322bf902ba28b99" + dependencies: + benchmark "1.0.0" + component-emitter "1.1.2" + debug "2.2.0" + isarray "0.0.1" + json3 "3.3.2" + +socket.io@1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.4.7.tgz#92b7f7cb88c5797d4daee279fe8075dbe6d3fa1c" + dependencies: + debug "2.2.0" + engine.io "1.6.10" + has-binary "0.1.7" + socket.io-adapter "0.4.0" + socket.io-client "1.4.6" + socket.io-parser "2.2.6" + +socket.io@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.5.0.tgz#024dd9719d9267d6a6984eebe2ab5ceb9a0b8a98" + dependencies: + debug "2.2.0" + engine.io "1.7.0" + has-binary "0.1.7" + socket.io-adapter "0.4.0" + socket.io-client "1.5.0" + socket.io-parser "2.2.6" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +source-map-support@^0.4.0, source-map-support@^0.4.2: + version "0.4.5" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.5.tgz#4438df4219e1b3c7feb674614b4c67f9722db1e4" + dependencies: + source-map "^0.5.3" + +source-map-support@~0.2.8: + version "0.2.10" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + dependencies: + source-map "0.1.32" + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@0.1.32: + version "0.1.32" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + dependencies: + amdefine ">=0.0.4" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +"statuses@>= 1.3.0 < 2", statuses@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.0.tgz#8e55758cb20e7682c1f4fce8dcab30bf01d1e07a" + +stream-throttle@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/stream-throttle/-/stream-throttle-0.1.3.tgz#add57c8d7cc73a81630d31cd55d3961cfafba9c3" + dependencies: + commander "^2.2.0" + limiter "^1.0.5" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" + dependencies: + has-flag "^1.0.0" + +svgo@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.1.tgz#287320fed972cb097e72c2bb1685f96fe08f8034" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.2.1" + js-yaml "~3.6.1" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +systemjs-builder@^0.15.20, systemjs-builder@0.15.32: + version "0.15.32" + resolved "https://registry.yarnpkg.com/systemjs-builder/-/systemjs-builder-0.15.32.tgz#66795f104792b0302eba40950f29ed53a791cc3e" + dependencies: + babel-core "^6.9.0" + babel-plugin-transform-cjs-system-wrapper "^0.2.1" + babel-plugin-transform-es2015-modules-systemjs "^6.6.5" + babel-plugin-transform-global-system-wrapper "0.0.1" + babel-plugin-transform-system-register "0.0.1" + bluebird "^3.3.4" + data-uri-to-buffer "0.0.4" + es6-template-strings "^2.0.0" + glob "^7.0.3" + mkdirp "^0.5.1" + rollup "^0.36.0" + source-map "^0.5.3" + systemjs "^0.19.39" + traceur "0.0.105" + uglify-js "^2.6.1" + +systemjs@^0.19.39, systemjs@0.19.39: + version "0.19.39" + resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-0.19.39.tgz#e513e6f91a25a37b8b607c51c7989ee0d67b9356" + dependencies: + when "^3.7.5" + +tar-fs@^1.13.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.14.0.tgz#f99cc074bf33bed21cd921a21720797bb18e6c96" + dependencies: + mkdirp "^0.5.0" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-pack@~3.1.0: + version "3.1.4" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.1.4.tgz#bc8cf9a22f5832739f12f3910dac1eb97b49708c" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar-stream@^1.1.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.2.tgz#fbc6c6e83c1a19d4cb48c7d96171fc248effc7bf" + dependencies: + bl "^1.0.0" + end-of-stream "^1.0.0" + readable-stream "^2.0.0" + xtend "^4.0.0" + +tar@^2.0.0, tar@~2.2.0, tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tfunk@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tfunk/-/tfunk-3.0.2.tgz#327ebc6176af2680c6cd0d6d22297c79d7f96efd" + dependencies: + chalk "^1.1.1" + object-path "^0.9.0" + +thenify-all@^1.0.0, thenify-all@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.2.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.2.1.tgz#251fd1c80aff6e5cf57cb179ab1fcb724269bd11" + dependencies: + any-promise "^1.0.0" + +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + +timers-ext@0.1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.0.tgz#00345a2ca93089d1251322054389d263e27b77e2" + dependencies: + es5-ext "~0.10.2" + next-tick "~0.2.2" + +tmp@0.0.28: + version "0.0.28" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + dependencies: + os-tmpdir "~1.0.1" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +tough-cookie@~2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" + +tough-cookie@~2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.1.tgz#99c77dfbb7d804249e8a299d4cb0fd81fef083fd" + +traceur@0.0.105: + version "0.0.105" + resolved "https://registry.yarnpkg.com/traceur/-/traceur-0.0.105.tgz#5cf9dee83d6b77861c3d6c44d53859aed7ab0479" + dependencies: + commander "2.9.x" + glob "5.0.x" + rsvp "^3.0.13" + semver "^4.3.3" + source-map-support "~0.2.8" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.3.tgz#3da382f670f25ded78d7b3d1792119bca0b7132d" + +type-is@~1.6.13: + version "1.6.13" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.13.tgz#6e83ba7bc30cd33a7bb0b7fb00737a2085bf9d08" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.11" + +typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +ua-parser-js@0.7.10: + version "0.7.10" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.10.tgz#917559ddcce07cbc09ece7d80495e4c268f4ef9f" + +uglify-js@^2.6.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.3.tgz#39b3a7329b89f5ec507e344c6e22568698ef4868" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +ultron@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + +unc-path-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + +underscore@1.7.x: + version "1.7.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqid@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.0.tgz#33d9679f65022f48988a03fd24e7dcaf8f109eca" + dependencies: + macaddress "^0.2.8" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unpipe@~1.0.0, unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +useragent@^2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.9.tgz#4dba2bc4dad1875777ab15de3ff8098b475000b7" + dependencies: + lru-cache "2.2.x" + +utf8@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.0.tgz#0cfec5c8052d44a23e3aaa908104e8075f95dfd5" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +vendors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +watch@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + +weinre@^2.0.0-pre-I0Z7U9OV: + version "2.0.0-pre-I0Z7U9OV" + resolved "https://registry.yarnpkg.com/weinre/-/weinre-2.0.0-pre-I0Z7U9OV.tgz#fef8aa223921f7b40bbbbd4c3ed4302f6fd0a813" + dependencies: + express "2.5.x" + nopt "3.0.x" + underscore "1.7.x" + +when@^3.7.5: + version "3.7.7" + resolved "https://registry.yarnpkg.com/when/-/when-3.7.7.tgz#aba03fc3bb736d6c88b091d013d8a8e590d84718" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@^1.0.9, which@^1.1.1, which@^1.2.10, which@^1.2.9, which@~1.2.10, which@1: + version "1.2.11" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.11.tgz#c8b2eeea6b8c1659fa7c1dd4fdaabe9533dc5e8b" + dependencies: + isexe "^1.1.1" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wrap-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.0.0.tgz#7d30f8f873f9a5bbc3a64dabc8d177e071ae426f" + dependencies: + string-width "^1.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +ws@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.0.1.tgz#7d0b2a2e58cddd819039c29c9de65045e1b310e9" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +ws@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +wtf-8@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + +xmlhttprequest-ssl@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.1.tgz#3b7741fea4a86675976e908d296d4445961faa67" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.0, y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + +yargs-parser@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.0.6" + +yargs-parser@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.0.2.tgz#7f7173a8c7cca1d81dc7c18692fc07c2c2e2b1e0" + dependencies: + camelcase "^3.0.0" + +yargs@^4.7.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.0.3" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.1" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^2.4.1" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +yargs@3.29.0: + version "3.29.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.29.0.tgz#1aab9660eae79d8b8f675bcaeeab6ee34c2cf69c" + dependencies: + camelcase "^1.2.1" + cliui "^3.0.3" + decamelize "^1.0.0" + os-locale "^1.4.0" + window-size "^0.1.2" + y18n "^3.2.0" + +yargs@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.0.0.tgz#900479df4e8bf6ab0e87216f5ed2b2760b968345" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^4.0.2" + +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + dependencies: + fd-slicer "~1.0.1" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + From f623800ef2ff04077ef3c0fdf2ebd73e51636496 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 17:16:43 +0200 Subject: [PATCH 446/593] chore(testing): Added test npm script for travis and fixed dependencies --- karma.ci.config.js | 27 +++++++++++++++++++++++++++ package.json | 22 +++++++++++----------- 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 karma.ci.config.js diff --git a/karma.ci.config.js b/karma.ci.config.js new file mode 100644 index 00000000..56a02843 --- /dev/null +++ b/karma.ci.config.js @@ -0,0 +1,27 @@ +module.exports = function(config) { + config.set({ + basePath: './', + frameworks: ['jasmine', 'jspm'], + autoWatch: false, + singleRun: true, + browsers: ['PhantomJS'], + files: [ + { pattern: 'src/**/*.+(js|html)', included: false }, + { pattern: 'tooling/**/*.js', included: false }, + { pattern: 'package.json', included: false }, + { pattern: 'jspm_packages/system-polyfills.js', included: false }, + 'dist/chartist.min.css' + ], + jspm: { + loadFiles: ['src/**/*.js'], + stripExtension: false, + config: 'jspm.config.js' + }, + proxies: { + '/jspm_packages/': '/base/jspm_packages/', + '/src/': '/base/src/', + '/tooling/': '/base/tooling/', + '/package.json': '/base/package.json' + } + }); +}; diff --git a/package.json b/package.json index c2184528..55df6472 100644 --- a/package.json +++ b/package.json @@ -39,16 +39,7 @@ "url": "https://github.com/chartist-js/chartist/blob/master/LICENSE-MIT" } ], - "dependencies": { - "autoprefixer": "^6.5.1", - "chokidar": "^1.6.1", - "cssnano": "^3.7.7", - "debounce": "^1.0.0", - "fs-promise": "^0.5.0", - "interpolate": "^0.1.0", - "node-sass": "^3.10.1", - "postcss": "^5.2.5" - }, + "dependencies": {}, "devDependencies": { "browser-sync": "^2.17.5", "jasmine-core": "^2.5.2", @@ -57,7 +48,15 @@ "karma-jasmine": "^1.0.2", "karma-jspm": "^2.2.0", "karma-nyan-reporter": "^0.2.4", - "karma-phantomjs-launcher": "^1.0.2" + "karma-phantomjs-launcher": "^1.0.2", + "autoprefixer": "^6.5.1", + "chokidar": "^1.6.1", + "cssnano": "^3.7.7", + "debounce": "^1.0.0", + "fs-promise": "^0.5.0", + "interpolate": "^0.1.0", + "node-sass": "^3.10.1", + "postcss": "^5.2.5" }, "engines": { "node": ">=6.9.0" @@ -74,6 +73,7 @@ }, "scripts": { "start": "yarn run test-watch & yarn run server & yarn run styles-watch", + "test": "./node_modules/.bin/karma start karma.ci.config.js", "test-watch": "./node_modules/.bin/karma start karma.watch.config.js", "styles-watch": "./tooling/node/styles-watch.js", "server": "./node_modules/.bin/browser-sync start --config 'bs-config.js'", From 668f92565f402b25a5320b4dd26765d0ff1bb4cc Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 17:19:28 +0200 Subject: [PATCH 447/593] chore(testing): Fixed travis config --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 405a6c49..08077c3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,3 @@ language: node_js node_js: - - '5.5.0' -before_script: - - 'npm install -g bower grunt-cli' - - 'bower install' + - '6.9.0' From 738b34c519540d80b4c358cee9eb9f495ea93535 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 17:22:09 +0200 Subject: [PATCH 448/593] chore(testing): Added jspm to travis --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 08077c3b..78129c84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,6 @@ language: node_js node_js: - '6.9.0' +before_script: + - 'npm install -g jspm' + - 'jspm install' From 1f677569eb38a888bbfa126d922fbbf8e0964f08 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 21:29:46 +0200 Subject: [PATCH 449/593] Fixed rounding issues where raw value was added instead of rounded, fixes #815 --- src/scripts/core.js | 2 +- test/spec/spec-core.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index b5688525..4f4428be 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -800,7 +800,7 @@ var Chartist = { for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { var value = Chartist.roundWithPrecision(i); if (value !== values[values.length - 1]) { - values.push(i); + values.push(value); } } bounds.values = values; diff --git a/test/spec/spec-core.js b/test/spec/spec-core.js index 61954109..4049883d 100644 --- a/test/spec/spec-core.js +++ b/test/spec/spec-core.js @@ -421,7 +421,7 @@ describe('Chartist core', function() { expect(bounds.max).toBe(1000); expect(bounds.low).toBe(999.9999999999997); expect(bounds.high).toBe(1000.0000000000001); - expect(bounds.values).toEqual([999.9999999999999]); + expect(bounds.values).toEqual([Chartist.roundWithPrecision(999.9999999999999)]); }); }); From 89b71b690a439d0598df6a42e8d047a74d94aef6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 21:40:41 +0200 Subject: [PATCH 450/593] fix(rounding): Fixed rounding issues and shadowing problem in roundWithPrecision --- src/core/data.js | 2 +- src/core/data.spec.js | 21 ++++++++++----------- src/core/math.js | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/core/data.js b/src/core/data.js index d3be0515..5c426b0d 100644 --- a/src/core/data.js +++ b/src/core/data.js @@ -474,7 +474,7 @@ export function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { var value = roundWithPrecision(i); if (value !== values[values.length - 1]) { - values.push(i); + values.push(value); } } bounds.values = values; diff --git a/src/core/data.spec.js b/src/core/data.spec.js index 86e5eec7..16b96592 100644 --- a/src/core/data.spec.js +++ b/src/core/data.spec.js @@ -1,4 +1,5 @@ import {serialize, deserialize, getDataArray, getBounds, splitIntoSegments} from './data'; +import {roundWithPrecision} from './math'; describe('Data', () => { describe('serialization', () => { @@ -274,16 +275,14 @@ describe('Data', () => { expect(bounds.values).toEqual([0]); }); - /* - TODO: This is currently failing with the ES6 refactoring and I can't tell why - it('should return single step if range is less than epsilon', () => { - const bounds = getBounds(100, { high: 1.0000000000000002, low: 1 }, 20, false); - expect(bounds.min).toBe(1); - expect(bounds.max).toBe(1.0000000000000002); - expect(bounds.low).toBe(1); - expect(bounds.high).toBe(1.0000000000000002); - expect(bounds.values).toEqual([1]); - });*/ + it('should return single step if range is less than epsilon', () => { + const bounds = getBounds(100, { high: 1.0000000000000002, low: 1 }, 20, false); + expect(bounds.min).toBe(1); + expect(bounds.max).toBe(1.0000000000000002); + expect(bounds.low).toBe(1); + expect(bounds.high).toBe(1.0000000000000002); + expect(bounds.values).toEqual([1]); + }); it('should return single step if range is less than smallest increment', () => { const bounds = getBounds(613.234375, {high: 1000.0000000000001, low: 999.9999999999997}, 50, false); @@ -291,7 +290,7 @@ describe('Data', () => { expect(bounds.max).toBe(1000); expect(bounds.low).toBe(999.9999999999997); expect(bounds.high).toBe(1000.0000000000001); - expect(bounds.values).toEqual([999.9999999999999]); + expect(bounds.values).toEqual([roundWithPrecision(999.9999999999999)]); }); }); diff --git a/src/core/math.js b/src/core/math.js index 529906bb..de5a11e9 100644 --- a/src/core/math.js +++ b/src/core/math.js @@ -1,4 +1,4 @@ -import {precision} from './globals'; +import {precision as globalPrecision} from './globals'; /** * Calculate the order of magnitude for the chart scale @@ -33,7 +33,7 @@ export function projectLength(axisLength, length, bounds) { * @returns {number} Rounded value */ export function roundWithPrecision(value, digits) { - var precision = Math.pow(10, digits || precision); + var precision = Math.pow(10, digits || globalPrecision); return Math.round(value * precision) / precision; } From bcd7d6e0331cc185497b3c941aa63ce9b68c99d9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 22:03:51 +0200 Subject: [PATCH 451/593] Latest dist --- CHANGELOG.md | 26 +- dist/chartist.css | 7 + dist/chartist.css.map | 2 +- dist/chartist.js | 459 +++++++++++++-------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 6 +- dist/chartist.min.js.map | 2 +- dist/scss/chartist.scss | 9 + dist/scss/settings/_chartist-settings.scss | 2 + package.json | 2 +- 10 files changed, 348 insertions(+), 169 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df1e0a07..69e17d8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +v0.10.0 - 23 Oct 2016 +--------------------- + +- Added dominant-baseline styles for pie and donut charts +- Added public getNode on SVG api +- Added support for bar charts to have auto narrowing on AutoScaleAxis by overriding referenceValue +- Added amdModuleId for better integration into webpack +- Added grid background to line and bar chart +- Added new LTS node version and included NPM run scripts +- Added correct meta data emission in events +- Fixed rounding issues where raw value was added instead of rounded +- Fixed step axis issue with axis stretch and series count 0 +- Fixed label position of single series pie / donut charts to be centered +- Fixed order or drawing pie and donut slices +- Fixed calculations of stepLength to only stretch ticksLength if > 1 +- Fixed better handling of axisOptions.position and fallback to 'end' position +- Fixed handling of holes in interpolation for multi-value series +- Fixed function StepAxis() returning NaN +- Fixed NaN issues in SVG when rendering Pie chart with only 0s +- Fixed infinite loop in getBounds with a more robust increment +- Fixed performance of Chartist.extend +- Fixed license reference issues in package.json +- Cleanup of data normalization changes and allows Date objects and booleans as values +- Cleanup refactoring for data management and normalization + v0.9.8 - 22 Jun 2016 -------------------- - Added monotone cubic interpolation which is now the default interpolation for line charts @@ -28,7 +53,6 @@ v0.9.6 - 22 Feb 2016 - Fix #527 Pie render issue with small angles. - Small fix for stacked bars with 'holes' in the data - v0.9.5 - 14 Nov 2015 -------------------- - Added 'fillHoles' option for line graphs, which continues the line smoothly through data holes (Thanks to Joshua Warner !) diff --git a/dist/chartist.css b/dist/chartist.css index 936025de..35f27d8f 100644 --- a/dist/chartist.css +++ b/dist/chartist.css @@ -13,6 +13,10 @@ display: -webkit-flex; display: flex; } +.ct-chart-pie .ct-label, +.ct-chart-donut .ct-label { + dominant-baseline: central; } + .ct-label.ct-horizontal.ct-start { -webkit-box-align: flex-end; -webkit-align-items: flex-end; @@ -138,6 +142,9 @@ stroke-width: 1px; stroke-dasharray: 2px; } +.ct-grid-background { + fill: none; } + .ct-point { stroke-width: 10px; stroke-linecap: round; } diff --git a/dist/chartist.css.map b/dist/chartist.css.map index 6bd28332..cee2d405 100644 --- a/dist/chartist.css.map +++ b/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/dist/chartist.js b/dist/chartist.js index 57220adc..050d0a62 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -1,7 +1,7 @@ (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module unless amdModuleId is set - define([], function () { + define('Chartist', [], function () { return (root['Chartist'] = factory()); }); } else if (typeof exports === 'object') { @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.9.8 +/* Chartist.js 0.10.0 * Copyright © 2016 Gion Kunz * Free to use under either the WTFPL license or the MIT license. * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL @@ -26,7 +26,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.9.8' + version: '0.10.0' }; (function (window, document, Chartist) { @@ -78,18 +78,20 @@ var Chartist = { * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source */ Chartist.extend = function (target) { + var i, source, sourceProp; target = target || {}; - var sources = Array.prototype.slice.call(arguments, 1); - sources.forEach(function(source) { + for (i = 1; i < arguments.length; i++) { + source = arguments[i]; for (var prop in source) { - if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) { - target[prop] = Chartist.extend({}, target[prop], source[prop]); + sourceProp = source[prop]; + if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { + target[prop] = Chartist.extend(target[prop], sourceProp); } else { - target[prop] = source[prop]; + target[prop] = sourceProp; } } - }); + } return target; }; @@ -351,37 +353,71 @@ var Chartist = { * @param {Object} data The data object that is passed as second argument to the charts * @return {Object} The normalized data object */ - Chartist.normalizeData = function(data) { - // Ensure data is present otherwise enforce - data = data || {series: [], labels: []}; - data.series = data.series || []; - data.labels = data.labels || []; + Chartist.normalizeData = function(data, reverse, multi) { + var labelCount; + var output = { + raw: data, + normalized: {} + }; // Check if we should generate some labels based on existing series data - if (data.series.length > 0 && data.labels.length === 0) { - var normalized = Chartist.getDataArray(data), - labelCount; + output.normalized.series = Chartist.getDataArray({ + series: data.series || [] + }, reverse, multi); - // If all elements of the normalized data array are arrays we're dealing with - // data from Bar or Line charts and we need to find the largest series if they are un-even - if (normalized.every(function(value) { + // If all elements of the normalized data array are arrays we're dealing with + // multi series data and we need to find the largest series if they are un-even + if (output.normalized.series.every(function(value) { return value instanceof Array; })) { - // Getting the series with the the most elements - labelCount = Math.max.apply(null, normalized.map(function(series) { - return series.length; - })); - } else { - // We're dealing with Pie data so we just take the normalized array length - labelCount = normalized.length; - } + // Getting the series with the the most elements + labelCount = Math.max.apply(null, output.normalized.series.map(function(series) { + return series.length; + })); + } else { + // We're dealing with Pie data so we just take the normalized array length + labelCount = output.normalized.series.length; + } - // Setting labels to an array with emptry strings using our labelCount estimated above - data.labels = Chartist.times(labelCount).map(function() { + output.normalized.labels = (data.labels || []).slice(); + // Padding the labels to labelCount with empty strings + Array.prototype.push.apply( + output.normalized.labels, + Chartist.times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() { return ''; - }); + }) + ); + + if(reverse) { + Chartist.reverseData(output.normalized); } - return data; + + return output; + }; + + /** + * This function safely checks if an objects has an owned property. + * + * @param {Object} object The object where to check for a property + * @param {string} property The property name + * @returns {boolean} Returns true if the object owns the specified property + */ + Chartist.safeHasProperty = function(object, property) { + return object !== null && + typeof object === 'object' && + object.hasOwnProperty(property); + }; + + /** + * Checks if a value is considered a hole in the data series. + * + * @param {*} value + * @returns {boolean} True if the value is considered a data hole + */ + Chartist.isDataHoleValue = function(value) { + return value === null || + value === undefined || + (typeof value === 'number' && isNaN(value)); }; /** @@ -407,30 +443,29 @@ var Chartist = { * * @memberof Chartist.Core * @param {Object} data The series object that contains the data to be visualized in the chart - * @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. - * @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. + * @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. + * @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. * @return {Array} A plain array that contains the data to be visualized in the chart */ - Chartist.getDataArray = function (data, reverse, multi) { - // If the data should be reversed but isn't we need to reverse it - // If it's reversed but it shouldn't we need to reverse it back - // That's required to handle data updates correctly and to reflect the responsive configurations - if(reverse && !data.reversed || !reverse && data.reversed) { - Chartist.reverseData(data); - data.reversed = !data.reversed; - } - + Chartist.getDataArray = function(data, reverse, multi) { // Recursively walks through nested arrays and convert string values to numbers and objects with value properties // to values. Check the tests in data core -> data normalization for a detailed specification of expected values function recursiveConvert(value) { - if(Chartist.isFalseyButZero(value)) { - // This is a hole in data and we should return undefined - return undefined; - } else if((value.data || value) instanceof Array) { - return (value.data || value).map(recursiveConvert); - } else if(value.hasOwnProperty('value')) { + if(Chartist.safeHasProperty(value, 'value')) { + // We are dealing with value object notation so we need to recurse on value property return recursiveConvert(value.value); + } else if(Chartist.safeHasProperty(value, 'data')) { + // We are dealing with series object notation so we need to recurse on data property + return recursiveConvert(value.data); + } else if(value instanceof Array) { + // Data is of type array so we need to recurse on the series + return value.map(recursiveConvert); + } else if(Chartist.isDataHoleValue(value)) { + // We're dealing with a hole in the data and therefore need to return undefined + // We're also returning undefined for multi value output + return undefined; } else { + // We need to prepare multi value output (x and y data) if(multi) { var multiValue = {}; @@ -449,6 +484,7 @@ var Chartist = { return multiValue; } else { + // We can return simple data return Chartist.getNumberOrUndefined(value); } } @@ -483,7 +519,7 @@ var Chartist = { Chartist.getMetaData = function(series, index) { var value = series.data ? series.data[index] : series[index]; - return value ? Chartist.serialize(value.meta) : undefined; + return value ? value.meta : undefined; }; /** @@ -599,14 +635,14 @@ var Chartist = { }; /** - * Checks if the value is a valid number or string with a number. + * 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. * * @memberof Chartist.Core * @param value * @returns {Boolean} */ - Chartist.isNum = function(value) { - return !isNaN(value) && isFinite(value); + Chartist.isNumeric = function(value) { + return value === null ? false : isFinite(value); }; /** @@ -628,23 +664,33 @@ var Chartist = { * @returns {*} */ Chartist.getNumberOrUndefined = function(value) { - return isNaN(+value) ? undefined : +value; + return Chartist.isNumeric(value) ? +value : undefined; }; /** - * 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 undefined. + * Checks if provided value object is multi value (contains x or y properties) * + * @memberof Chartist.Core + * @param value + */ + Chartist.isMultiValue = function(value) { + return typeof value === 'object' && ('x' in value || 'y' in value); + }; + + /** + * 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`. + * + * @memberof Chartist.Core * @param value * @param dimension + * @param defaultValue * @returns {*} */ Chartist.getMultiValue = function(value, dimension) { - if(Chartist.isNum(value)) { - return +value; - } else if(value) { - return value[dimension || 'y'] || 0; + if(Chartist.isMultiValue(value)) { + return Chartist.getNumberOrUndefined(value[dimension || 'y']); } else { - return 0; + return Chartist.getNumberOrUndefined(value); } }; @@ -749,28 +795,34 @@ var Chartist = { } } - // step must not be less than EPSILON to create values that can be represented as floating number. var EPSILON = 2.221E-16; bounds.step = Math.max(bounds.step, EPSILON); + function safeIncrement(value, increment) { + // If increment is too small use *= (1+EPSILON) as a simple nextafter + if (value === (value += increment)) { + value *= (1 + (increment > 0 ? EPSILON : -EPSILON)); + } + return value; + } // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; - while(newMin + bounds.step <= bounds.low) { - newMin += bounds.step; + while (newMin + bounds.step <= bounds.low) { + newMin = safeIncrement(newMin, bounds.step); } - while(newMax - bounds.step >= bounds.high) { - newMax -= bounds.step; + while (newMax - bounds.step >= bounds.high) { + newMax = safeIncrement(newMax, -bounds.step); } bounds.min = newMin; bounds.max = newMax; bounds.range = bounds.max - bounds.min; var values = []; - for (i = bounds.min; i <= bounds.max; i += bounds.step) { + for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { var value = Chartist.roundWithPrecision(i); if (value !== values[values.length - 1]) { - values.push(i); + values.push(value); } } bounds.values = values; @@ -888,6 +940,31 @@ var Chartist = { ); }; + /** + * Creates a grid background rect and emits the draw event. + * + * @memberof Chartist.Core + * @param gridGroup + * @param chartRect + * @param className + * @param eventEmitter + */ + Chartist.createGridBackground = function (gridGroup, chartRect, className, eventEmitter) { + var gridBackground = gridGroup.elem('rect', { + x: chartRect.x1, + y: chartRect.y2, + width: chartRect.width(), + height: chartRect.height(), + }, className, true); + + // Event for grid background draw + eventEmitter.emit('draw', { + type: 'gridBackground', + group: gridGroup, + element: gridBackground + }); + }; + /** * Creates a label based on a projected value and an axis. * @@ -1057,7 +1134,8 @@ var Chartist = { for(var i = 0; i < pathCoordinates.length; i += 2) { // If this value is a "hole" we set the hole flag - if(valueData[i / 2].value === undefined) { + if(Chartist.getMultiValue(valueData[i / 2].value) === undefined) { + // if(valueData[i / 2].value === undefined) { if(!options.fillHoles) { hole = true; } @@ -1129,7 +1207,7 @@ var Chartist = { var currY = pathCoordinates[i + 1]; var currData = valueData[i / 2]; - if(currData.value !== undefined) { + if(Chartist.getMultiValue(currData.value) !== undefined) { if(hole) { path.move(currX, currY, false, currData); @@ -1738,7 +1816,9 @@ var Chartist = { */ function update(data, options, override) { if(data) { - this.data = data; + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; // Event for data transformation that allows to manipulate the data before it gets rendered in the charts this.eventEmitter.emit('data', { type: 'update', @@ -1858,7 +1938,9 @@ var Chartist = { */ function Base(query, data, defaultOptions, options, responsiveOptions) { this.container = Chartist.querySelector(query); - this.data = data; + this.data = data || {}; + this.data.labels = this.data.labels || []; + this.data.series = this.data.series || []; this.defaultOptions = defaultOptions; this.options = options; this.responsiveOptions = responsiveOptions; @@ -1959,7 +2041,7 @@ var Chartist = { * * @memberof Chartist.Svg * @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. - * @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. + * @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. * @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. */ function attr(attributes, ns) { @@ -2050,6 +2132,16 @@ var Chartist = { return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; } + /** + * Returns the underlying SVG node for the current element. + * + * @memberof Chartist.Svg + * @returns {Node} + */ + function getNode() { + return this._node; + } + /** * 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. * @@ -2167,10 +2259,13 @@ var Chartist = { * @return {Chartist.Svg} The wrapper of the current element */ function addClass(names) { - var arr = this.classes(this._node).concat(names.trim().split(/\s+/)); - this._node.setAttribute('class', arr.filter(function(elem, pos) { - return arr.indexOf(elem) === pos; - }).join(' ')); + this._node.setAttribute('class', + this.classes(this._node) + .concat(names.trim().split(/\s+/)) + .filter(function(elem, pos, self) { + return self.indexOf(elem) === pos; + }).join(' ') + ); return this; } @@ -2384,6 +2479,7 @@ var Chartist = { root: root, querySelector: querySelector, querySelectorAll: querySelectorAll, + getNode: getNode, foreignObject: foreignObject, text: text, empty: empty, @@ -2970,7 +3066,7 @@ var Chartist = { Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [ chartOptions.classNames.label, chartOptions.classNames[this.units.dir], - chartOptions.classNames[axisOptions.position] + (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']) ], useForeignObject, eventEmitter); } }.bind(this)); @@ -3014,7 +3110,7 @@ var Chartist = { function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options - var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); this.range = { min: this.bounds.min, @@ -3062,7 +3158,7 @@ var Chartist = { 'use strict'; function FixedScaleAxis(axisUnit, data, chartRect, options) { - var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos); + var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return highLow.low + (highLow.high - highLow.low) / this.divisor * index; @@ -3120,7 +3216,8 @@ var Chartist = { options.ticks, options); - this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0)); + var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0)); + this.stepLength = this.axisLength / calc; } function projectValue(value, index) { @@ -3208,6 +3305,8 @@ var Chartist = { areaBase: 0, // 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. lineSmooth: true, + // If the line chart should add a background fill to the .ct-grids group. + showGridBackground: false, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value @@ -3234,6 +3333,7 @@ var Chartist = { area: 'ct-area', grid: 'ct-grid', gridGroup: 'ct-grids', + gridBackground: 'ct-grid-background', vertical: 'ct-vertical', horizontal: 'ct-horizontal', start: 'ct-start', @@ -3246,11 +3346,7 @@ var Chartist = { * */ function createChart(options) { - this.data = Chartist.normalizeData(this.data); - var data = { - raw: this.data, - normalized: Chartist.getDataArray(this.data, options.reverseData, true) - }; + var data = Chartist.normalizeData(this.data, options.reverseData, true); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); @@ -3263,26 +3359,30 @@ var Chartist = { var axisX, axisY; if(options.axisX.type === undefined) { - axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { - ticks: data.raw.labels, + axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { + ticks: data.normalized.labels, stretch: options.fullWidth })); } else { - axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX); } if(options.axisY.type === undefined) { - axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { - high: Chartist.isNum(options.high) ? options.high : options.axisY.high, - low: Chartist.isNum(options.low) ? options.low : options.axisY.low + axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { + high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high, + low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low })); } else { - axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY); } axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + if (options.showGridBackground) { + Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + // Draw the series data.raw.series.forEach(function(series, seriesIndex) { var seriesElement = seriesGroup.elem('g'); @@ -3302,10 +3402,10 @@ var Chartist = { var pathCoordinates = [], pathData = []; - data.normalized[seriesIndex].forEach(function(value, valueIndex) { + data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { var p = { - x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex]) }; pathCoordinates.push(p.x, p.y); pathData.push({ @@ -3341,8 +3441,8 @@ var Chartist = { x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ - 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','), - 'ct:meta': pathElement.data.meta + 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','), + 'ct:meta': Chartist.serialize(pathElement.data.meta) }); this.eventEmitter.emit('draw', { @@ -3369,12 +3469,13 @@ var Chartist = { this.eventEmitter.emit('draw', { type: 'line', - values: data.normalized[seriesIndex], + values: data.normalized.series[seriesIndex], path: path.clone(), chartRect: chartRect, index: seriesIndex, series: series, seriesIndex: seriesIndex, + seriesMeta: series.meta, axisX: axisX, axisY: axisY, group: seriesElement, @@ -3422,7 +3523,7 @@ var Chartist = { // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { type: 'area', - values: data.normalized[seriesIndex], + values: data.normalized.series[seriesIndex], path: areaPath.clone(), series: series, seriesIndex: seriesIndex, @@ -3611,6 +3712,8 @@ var Chartist = { high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, + // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale. + referenceValue: 0, // 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} chartPadding: { top: 15, @@ -3631,6 +3734,8 @@ var Chartist = { distributeSeries: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. reverseData: false, + // If the bar chart should add a background fill to the .ct-grids group. + showGridBackground: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', @@ -3641,6 +3746,7 @@ var Chartist = { bar: 'ct-bar', grid: 'ct-grid', gridGroup: 'ct-grids', + gridBackground: 'ct-grid-background', vertical: 'ct-vertical', horizontal: 'ct-horizontal', start: 'ct-start', @@ -3653,16 +3759,18 @@ var Chartist = { * */ function createChart(options) { - this.data = Chartist.normalizeData(this.data); - var data = { - raw: this.data, - normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) { - return [value]; - }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y') - }; - + var data; var highLow; + if(options.distributeSeries) { + data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + data.normalized.series = data.normalized.series.map(function(value) { + return [value]; + }); + } else { + data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); + } + // Create new svg element this.svg = Chartist.createSvg( this.container, @@ -3676,9 +3784,10 @@ var Chartist = { var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); - if(options.stackBars && data.normalized.length !== 0) { + if(options.stackBars && data.normalized.series.length !== 0) { + // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = Chartist.serialMap(data.normalized, function serialSums() { + var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { return value; }).reduce(function(prev, curr) { @@ -3689,14 +3798,13 @@ var Chartist = { }, {x: 0, y: 0}); }); - highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, { - referenceValue: 0 - }), options.horizontalBars ? 'x' : 'y'); + highLow = Chartist.getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y'); + } else { - highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, { - referenceValue: 0 - }), options.horizontalBars ? 'x' : 'y'); + + highLow = Chartist.getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y'); } + // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); @@ -3713,51 +3821,51 @@ var Chartist = { if(options.distributeSeries && options.stackBars) { // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should // use only the first label for the step axis - labelAxisTicks = data.raw.labels.slice(0, 1); + labelAxisTicks = data.normalized.labels.slice(0, 1); } else { // If distributed series are enabled but stacked bars aren't, we should use the series labels // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array // as the bars are normalized - labelAxisTicks = data.raw.labels; + labelAxisTicks = data.normalized.labels; } // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { if(options.axisX.type === undefined) { - valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, referenceValue: 0 })); } else { - valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, { + valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, referenceValue: 0 })); } if(options.axisY.type === undefined) { - labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, { + labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, { ticks: labelAxisTicks }); } else { - labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY); + labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY); } } else { if(options.axisX.type === undefined) { - labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, { + labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, { ticks: labelAxisTicks }); } else { - labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX); + labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX); } if(options.axisY.type === undefined) { - valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); } else { - valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, { + valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); @@ -3772,6 +3880,10 @@ var Chartist = { labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); + if (options.showGridBackground) { + Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); + } + // Draw the series data.raw.series.forEach(function(series, seriesIndex) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. @@ -3785,14 +3897,14 @@ var Chartist = { if(options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array // which is the series count and divide by 2 - periodHalfLength = labelAxis.axisLength / data.normalized.length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2; } else if(options.distributeSeries && options.stackBars) { // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis // length by 2 periodHalfLength = labelAxis.axisLength / 2; } else { // On regular bar charts we should just use the series length - periodHalfLength = labelAxis.axisLength / data.normalized[seriesIndex].length / 2; + periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2; } // Adding the series group to the series element @@ -3810,7 +3922,7 @@ var Chartist = { (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); - data.normalized[seriesIndex].forEach(function(value, valueIndex) { + data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { var projected, bar, previousStack, @@ -3833,13 +3945,13 @@ var Chartist = { // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { - x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]) }; } else { projected = { - x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]), - y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[seriesIndex]) + x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]), + y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex]) } } @@ -3889,17 +4001,19 @@ var Chartist = { positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); + var metaData = Chartist.getMetaData(series, valueIndex); + // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ - 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','), - 'ct:meta': Chartist.getMetaData(series, valueIndex) + 'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','), + 'ct:meta': Chartist.serialize(metaData) }); this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', value: value, index: valueIndex, - meta: Chartist.getMetaData(series, valueIndex), + meta: metaData, series: series, seriesIndex: seriesIndex, axisX: axisX, @@ -4057,15 +4171,14 @@ var Chartist = { * @param options */ function createChart(options) { - this.data = Chartist.normalizeData(this.data); + var data = Chartist.normalizeData(this.data); var seriesGroups = [], labelsGroup, chartRect, radius, labelRadius, totalDataSum, - startAngle = options.startAngle, - dataArray = Chartist.getDataArray(this.data, options.reverseData); + startAngle = options.startAngle; // Create SVG.js draw this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie); @@ -4074,7 +4187,7 @@ var Chartist = { // Get biggest circle radius possible within chartRect radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) { + totalDataSum = options.total || data.normalized.series.reduce(function(previousValue, currentValue) { return previousValue + currentValue; }, 0); @@ -4110,39 +4223,41 @@ var Chartist = { }; // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = this.data.series.filter(function(val) { + var hasSingleValInSeries = data.raw.series.filter(function(val) { return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; + // Creating the series groups + data.raw.series.forEach(function(series, index) { + seriesGroups[index] = this.svg.elem('g', null, null); + }.bind(this)); //if we need to show labels we create the label group now if(options.showLabel) { - labelsGroup = this.svg.elem('g', null, null, true); + labelsGroup = this.svg.elem('g', null, null); } // Draw the series // initialize series groups - for (var i = 0; i < this.data.series.length; i++) { + data.raw.series.forEach(function(series, index) { // If current value is zero and we are ignoring empty values then skip to next value - if (dataArray[i] === 0 && options.ignoreEmptyValues) continue; - - var series = this.data.series[i]; - seriesGroups[i] = this.svg.elem('g', null, null, true); + if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; // If the series is an object and contains a name or meta data we add a custom attribute - seriesGroups[i].attr({ + seriesGroups[index].attr({ 'ct:series-name': series.name }); // Use series class from series data or if not set generate one - seriesGroups[i].addClass([ + seriesGroups[index].addClass([ options.classNames.series, - (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i)) + (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(index)) ].join(' ')); - var endAngle = startAngle + dataArray[i] / totalDataSum * 360; + // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. + var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0); // Use slight offset so there are no transparent hairline issues - var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2)); + var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees @@ -4165,13 +4280,13 @@ var Chartist = { // Create the SVG path // If this is a donut chart we add the donut class, otherwise just a regular slice - var pathElement = seriesGroups[i].elem('path', { + var pathElement = seriesGroups[index].elem('path', { d: path.stringify() }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie); // Adding the pie series value to the path pathElement.attr({ - 'ct:value': dataArray[i], + 'ct:value': data.normalized.series[index], 'ct:meta': Chartist.serialize(series.meta) }); @@ -4185,12 +4300,12 @@ var Chartist = { // Fire off draw event this.eventEmitter.emit('draw', { type: 'slice', - value: dataArray[i], + value: data.normalized.series[index], totalDataSum: totalDataSum, - index: i, + index: index, meta: series.meta, series: series, - group: seriesGroups[i], + group: seriesGroups[index], element: pathElement, path: path.clone(), center: center, @@ -4201,9 +4316,31 @@ var Chartist = { // If we need to show labels we need to add the label for this slice now if(options.showLabel) { - // Position at the labelRadius distance from center and between start and end angle - var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2), - interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i); + var labelPosition; + if(data.raw.series.length === 1) { + // If we have only 1 series, we can position the label in the center of the pie + labelPosition = { + x: center.x, + y: center.y + }; + } else { + // Position at the labelRadius distance from center and between start and end angle + labelPosition = Chartist.polarToCartesian( + center.x, + center.y, + labelRadius, + startAngle + (endAngle - startAngle) / 2 + ); + } + + var rawValue; + if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) { + rawValue = data.normalized.labels[index]; + } else { + rawValue = data.normalized.series[index]; + } + + var interpolatedValue = options.labelInterpolationFnc(rawValue, index); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { @@ -4215,7 +4352,7 @@ var Chartist = { // Fire off draw event this.eventEmitter.emit('draw', { type: 'label', - index: i, + index: index, group: labelsGroup, element: labelElement, text: '' + interpolatedValue, @@ -4228,7 +4365,7 @@ var Chartist = { // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; - } + }.bind(this)); this.eventEmitter.emit('created', { chartRect: chartRect, diff --git a/dist/chartist.min.css b/dist/chartist.min.css index e1c280e5..9f9b908e 100644 --- a/dist/chartist.min.css +++ b/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-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-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{fill:none;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-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 diff --git a/dist/chartist.min.js b/dist/chartist.min.js index ca5e4ef2..e0fec43c 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,10 +1,10 @@ -/* Chartist.js 0.9.8 +/* Chartist.js 0.10.0 * Copyright © 2016 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([],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.9.8"};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){a=a||{};var b=Array.prototype.slice.call(arguments,1);return b.forEach(function(b){for(var d in b)"object"!=typeof b[d]||null===b[d]||b[d]instanceof Array?a[d]=b[d]:a[d]=c.extend({},a[d],b[d])}),a},c.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},c.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},c.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},c.querySelector=function(a){return a instanceof Node?a:b.querySelector(a)},c.times=function(a){return Array.apply(null,new Array(a))},c.sum=function(a,b){return a+(b?b:0)},c.mapMultiply=function(a){return function(b){return b*a}},c.mapAdd=function(a){return function(b){return b+a}},c.serialMap=function(a,b){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return c.times(e).forEach(function(c,e){var f=a.map(function(a){return a[e]});d[e]=b.apply(null,f)}),d},c.roundWithPrecision=function(a,b){var d=Math.pow(10,b||c.precision);return Math.round(a*d)/d},c.precision=8,c.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},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){if(a=a||{series:[],labels:[]},a.series=a.series||[],a.labels=a.labels||[],a.series.length>0&&0===a.labels.length){var b,d=c.getDataArray(a);b=d.every(function(a){return a instanceof Array})?Math.max.apply(null,d.map(function(a){return a.length})):d.length,a.labels=c.times(b).map(function(){return""})}return 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.isNum=function(a){return!isNaN(a)&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return isNaN(+a)?void 0:+a},c.getMultiValue=function(a,b){return c.isNum(a)?+a:a?a[b||"y"]||0:0},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){var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=c.orderOfMagnitude(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=c.projectLength(a,j.step,j),l=k=d)j.step=1;else if(e&&m=d)j.step=m;else for(;;){if(l&&c.projectLength(a,j.step,j)<=d)j.step*=2;else{if(l||!(c.projectLength(a,j.step/2,j)>=d))break;if(j.step/=2,e&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var n=2.221e-16;for(j.step=Math.max(j.step,n),g=j.min,h=j.max;g+j.step<=j.low;)g+=j.step;for(;h-j.step>=j.high;)h-=j.step;j.min=g,j.max=h,j.range=j.max-j.min;var o=[];for(f=j.min;f<=j.max;f+=j.step){var p=c.roundWithPrecision(f);p!==o[o.length-1]&&o.push(f)}return j.values=o,j},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.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[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,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",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){this.data=c.normalizeData(this.data);var b,d={raw:this.data,normalized:a.distributeSeries?c.getDataArray(this.data,a.reverseData,a.horizontalBars?"x":"y").map(function(a){return[a]}):c.getDataArray(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!==d.normalized.length){var i=c.serialMap(d.normalized,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})});b=c.getHighLow([i],c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y")}else b=c.getHighLow(d.normalized,c.extend({},a,{referenceValue:0}),a.horizontalBars?"x":"y");b.high=+a.high||(0===a.high?0:b.high),b.low=+a.low||(0===a.low?0:b.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?d.raw.labels.slice(0,1):d.raw.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,d,o,c.extend({},a.axisX,{highLow:b,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,d,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,d,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,d,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,d,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,d,o,c.extend({},a.axisY,{highLow:b,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),d.raw.series.forEach(function(b,e){var f,h,i=e-(d.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/d.normalized.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/d.normalized[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":b.name,"ct:meta":c.serialize(b.meta)}),h.addClass([a.classNames.series,b.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),d.normalized[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,d.normalized[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,d.normalized[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,d.normalized[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,d.normalized[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),s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNum).join(","),"ct:meta":c.getMetaData(b,k)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:c.getMetaData(b,k),series:b,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,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!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",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){this.data=c.normalizeData(this.data);var b,e,f,h,i,j=[],k=a.startAngle,l=c.getDataArray(this.data,a.reverseData);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||l.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===this.data.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;a.showLabel&&(b=this.svg.elem("g",null,null,!0));for(var p=0;p=359.99&&(r=s+359.99);var t=c.polarToCartesian(n.x,n.y,f,s),u=c.polarToCartesian(n.x,n.y,f,r),v=new c.Svg.Path((!a.donut)).move(u.x,u.y).arc(f,f,0,r-k>180,0,t.x,t.y);a.donut||v.line(n.x,n.y);var w=j[p].elem("path",{d:v.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(w.attr({"ct:value":l[p],"ct:meta":c.serialize(q.meta)}),a.donut&&w.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:l[p],totalDataSum:i,index:p,meta:q.meta,series:q,group:j[p],element:w,path:v.clone(),center:n,radius:f,startAngle:k,endAngle:r}),a.showLabel){var x=c.polarToCartesian(n.x,n.y,h,k+(r-k)/2),y=a.labelInterpolationFnc(this.data.labels&&!c.isFalseyButZero(this.data.labels[p])?this.data.labels[p]:l[p],p);if(y||0===y){var z=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":d(n,x,a.labelDirection)},a.classNames.label).text(""+y);this.eventEmitter.emit("draw",{type:"label",index:p,group:b,element:z,text:""+y,x:x.x,y:x.y})}}k=r}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 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}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index 6d39d513..7006d742 100644 --- a/dist/chartist.min.js.map +++ b/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","sources","Array","prototype","slice","call","arguments","forEach","source","prop","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","length","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","series","labels","labelCount","normalized","getDataArray","every","reverseData","reverse","i","multi","recursiveConvert","isFalseyButZero","hasOwnProperty","multiValue","getNumberOrUndefined","y","x","reversed","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","isNum","isNaN","isFinite","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","EPSILON","values","push","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","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","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","gridGroup","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","stretch","raw","chart","seriesGroup","fullWidth","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","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","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","dataArray","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","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([], 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.9.8\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.9.8'\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 target = target || {};\n\n var sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n for (var prop in source) {\n if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {\n target[prop] = Chartist.extend({}, target[prop], source[prop]);\n } else {\n target[prop] = source[prop];\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) {\n // Ensure data is present otherwise enforce\n data = data || {series: [], labels: []};\n data.series = data.series || [];\n data.labels = data.labels || [];\n\n // Check if we should generate some labels based on existing series data\n if (data.series.length > 0 && data.labels.length === 0) {\n var normalized = Chartist.getDataArray(data),\n labelCount;\n\n // If all elements of the normalized data array are arrays we're dealing with\n // data from Bar or Line charts and we need to find the largest series if they are un-even\n if (normalized.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, normalized.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 = normalized.length;\n }\n\n // Setting labels to an array with emptry strings using our labelCount estimated above\n data.labels = Chartist.times(labelCount).map(function() {\n return '';\n });\n }\n return data;\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 // If the data should be reversed but isn't we need to reverse it\n // If it's reversed but it shouldn't we need to reverse it back\n // That's required to handle data updates correctly and to reflect the responsive configurations\n if(reverse && !data.reversed || !reverse && data.reversed) {\n Chartist.reverseData(data);\n data.reversed = !data.reversed;\n }\n\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.isFalseyButZero(value)) {\n // This is a hole in data and we should return undefined\n return undefined;\n } else if((value.data || value) instanceof Array) {\n return (value.data || value).map(recursiveConvert);\n } else if(value.hasOwnProperty('value')) {\n return recursiveConvert(value.value);\n } else {\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 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 ? Chartist.serialize(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 the value is a valid number or string with a number.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNum = function(value) {\n return !isNaN(value) && 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 isNaN(+value) ? undefined : +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 undefined.\n *\n * @param value\n * @param dimension\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isNum(value)) {\n return +value;\n } else if(value) {\n return value[dimension || 'y'] || 0;\n } else {\n return 0;\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 // step must not be less than EPSILON to create values that can be represented as floating number.\n var EPSILON = 2.221E-16;\n bounds.step = Math.max(bounds.step, EPSILON);\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 newMin += bounds.step;\n }\n while(newMax - bounds.step >= bounds.high) {\n 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 += bounds.step) {\n var value = Chartist.roundWithPrecision(i);\n if (value !== values[values.length - 1]) {\n values.push(i);\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 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(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(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 // 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.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 * 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 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 chartOptions.classNames[axisOptions.position]\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.normalized, 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.normalized, 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 this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));\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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: Chartist.getDataArray(this.data, options.reverseData, true)\n };\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, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.raw.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNum(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNum(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, 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 // 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[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[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.isNum).join(','),\n 'ct:meta': 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[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\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[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 // 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 // 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 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 this.data = Chartist.normalizeData(this.data);\n var data = {\n raw: this.data,\n normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {\n return [value];\n }) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')\n };\n\n var highLow;\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.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized, 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], Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\n } else {\n highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {\n referenceValue: 0\n }), options.horizontalBars ? 'x' : 'y');\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.raw.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.raw.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, 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, 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, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, 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, 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 // 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.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[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[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[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[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 // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),\n 'ct:meta': Chartist.getMetaData(series, valueIndex)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex),\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 this.data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle,\n dataArray = Chartist.getDataArray(this.data, options.reverseData);\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 || dataArray.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 = this.data.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\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, true);\n }\n\n // Draw the series\n // initialize series groups\n for (var i = 0; i < this.data.series.length; i++) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;\n\n var series = this.data.series[i];\n seriesGroups[i] = this.svg.elem('g', null, null, true);\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[i].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[i].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))\n ].join(' '));\n\n var endAngle = startAngle + dataArray[i] / totalDataSum * 360;\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (i === 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[i].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': dataArray[i],\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: dataArray[i],\n totalDataSum: totalDataSum,\n index: i,\n meta: series.meta,\n series: series,\n group: seriesGroups[i],\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 // Position at the labelRadius distance from center and between start and end angle\n var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),\n interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);\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: i,\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 }\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","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 diff --git a/dist/scss/chartist.scss b/dist/scss/chartist.scss index 0f19ba05..e3caaa6b 100644 --- a/dist/scss/chartist.scss +++ b/dist/scss/chartist.scss @@ -123,6 +123,11 @@ @include ct-flex(); } + .#{$ct-class-chart-pie} .#{$ct-class-label}, + .#{$ct-class-chart-donut} .#{$ct-class-label} { + dominant-baseline: central; + } + .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { @include ct-align-justify(flex-end, flex-start); // Fallback for browsers that don't support foreignObjects @@ -188,6 +193,10 @@ @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); } + .#{$ct-class-grid-background} { + fill: $ct-grid-background-fill; + } + .#{$ct-class-point} { @include ct-chart-point($ct-point-size, $ct-point-shape); } diff --git a/dist/scss/settings/_chartist-settings.scss b/dist/scss/settings/_chartist-settings.scss index 21b92c13..4d0370eb 100644 --- a/dist/scss/settings/_chartist-settings.scss +++ b/dist/scss/settings/_chartist-settings.scss @@ -18,6 +18,7 @@ $ct-class-bar: ct-bar !default; $ct-class-slice-pie: ct-slice-pie !default; $ct-class-slice-donut: ct-slice-donut !default; $ct-class-grid: ct-grid !default; +$ct-class-grid-background: ct-grid-background !default; $ct-class-vertical: ct-vertical !default; $ct-class-horizontal: ct-horizontal !default; $ct-class-start: ct-start !default; @@ -37,6 +38,7 @@ $ct-text-line-height: 1; $ct-grid-color: rgba(0, 0, 0, 0.2) !default; $ct-grid-dasharray: 2px !default; $ct-grid-width: 1px !default; +$ct-grid-background-fill: none !default; // Line chart properties $ct-line-width: 4px !default; diff --git a/package.json b/package.json index 58692e3b..2022f949 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.9.8", + "version": "0.10.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 2ef08e5a52f4cea96a1fc8a7521971340a106a5a Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Sun, 23 Oct 2016 22:14:54 +0200 Subject: [PATCH 452/593] Fixed changelog --- CHANGELOG.md | 82 ++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69e17d8b..8efd792f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,39 +1,39 @@ v0.10.0 - 23 Oct 2016 --------------------- -- Added dominant-baseline styles for pie and donut charts -- Added public getNode on SVG api -- Added support for bar charts to have auto narrowing on AutoScaleAxis by overriding referenceValue -- Added amdModuleId for better integration into webpack -- Added grid background to line and bar chart -- Added new LTS node version and included NPM run scripts -- Added correct meta data emission in events -- Fixed rounding issues where raw value was added instead of rounded -- Fixed step axis issue with axis stretch and series count 0 -- Fixed label position of single series pie / donut charts to be centered -- Fixed order or drawing pie and donut slices -- Fixed calculations of stepLength to only stretch ticksLength if > 1 -- Fixed better handling of axisOptions.position and fallback to 'end' position -- Fixed handling of holes in interpolation for multi-value series -- Fixed function StepAxis() returning NaN -- Fixed NaN issues in SVG when rendering Pie chart with only 0s -- Fixed infinite loop in getBounds with a more robust increment -- Fixed performance of Chartist.extend -- Fixed license reference issues in package.json -- Cleanup of data normalization changes and allows Date objects and booleans as values -- Cleanup refactoring for data management and normalization +- Added dominant-baseline styles for pie and donut charts (Gion Kunz) +- Added public getNode on SVG api (Gion Kunz) +- Added support for bar charts to have auto narrowing on AutoScaleAxis by overriding referenceValue (Jonathan Dumaine) +- Added amdModuleId for better integration into webpack (Chris) +- Added grid background to line and bar chart (hansmaad) +- Added new LTS node version and included NPM run scripts (Gion Kunz) +- Added correct meta data emission in events (Gion Kunz) +- Fixed rounding issues where raw value was added instead of rounded (Gion Kunz) +- Fixed step axis issue with axis stretch and series count 0 (Gion Kunz) +- Fixed label position of single series pie / donut charts to be centered (Gion Kunz) +- Fixed order or drawing pie and donut slices (Gion Kunz) +- Fixed calculations of stepLength to only stretch ticksLength if > 1 (Alexander van Eck) +- Fixed better handling of axisOptions.position and fallback to 'end' position (Alexander van Eck) +- Fixed handling of holes in interpolation for multi-value series (James Watmuff) +- Fixed function StepAxis() returning NaN (Joao Milton) +- Fixed NaN issues in SVG when rendering Pie chart with only 0s (Alexander van Eck) +- Fixed infinite loop in getBounds with a more robust increment (hansmaad) +- Fixed performance of Chartist.extend (cheese83) +- Fixed license reference issues in package.json (Jacob Quant) +- Cleanup of data normalization changes and allows Date objects and booleans as values (Gion Kunz) +- Cleanup refactoring for data management and normalization (Gion Kunz) v0.9.8 - 22 Jun 2016 -------------------- -- Added monotone cubic interpolation which is now the default interpolation for line charts -- Update zoom plugin to 0.2.1 -- Bugfix: Prevent infinite loop in getBounds if bounds.valueRange is very small, fixes #643 -- Bugfix: Correct update events during media changes -- Bugfix: prevent negative value for foreignObject width attribute -- Fixed example line chart in getting started documentation -- Updated development pipeline dependencies -- Updated chartist tooltip plugin and example styles -- Fixed WTFPL License issue +- Added monotone cubic interpolation which is now the default interpolation for line charts (James Watmuff) +- Update zoom plugin to 0.2.1 (hansmaad) +- Bugfix: Prevent infinite loop in getBounds if bounds.valueRange is very small, fixes #643 (hansmaad) +- Bugfix: Correct update events during media changes (Rory Hunter) +- Bugfix: prevent negative value for foreignObject width attribute (Jose Ignacio) +- Fixed example line chart in getting started documentation (Robin Edbom) +- Updated development pipeline dependencies (Gion Kunz) +- Updated chartist tooltip plugin and example styles (Gion Kunz) +- Fixed WTFPL License issue (Gion Kunz) v0.9.7 - 23 Feb 2016 -------------------- @@ -41,17 +41,17 @@ v0.9.7 - 23 Feb 2016 v0.9.6 - 22 Feb 2016 -------------------- -- Added dual licensing WTFPL and MIT, built new version -- Adding unminified CSS to dist output, fixes #506 -- Refactored namespaced attribute handling, fixes #584 -- Allow charts to be created without data and labels, fixes #598, fixes #588, fixes #537, fixes #425 -- Removed onlyInteger setting from default bar chart settings, fixes #423 -- Removed serialization of values on line chart areas, fixes #424 -- Removed workaround and fallback for SVG element width and height calculations, fixes #592 -- Render 0 in ct:value attribute for line graphs -- Allow empty pie chart values to be ignored -- Fix #527 Pie render issue with small angles. -- Small fix for stacked bars with 'holes' in the data +- Added dual licensing WTFPL and MIT, built new version (Gion Kunz) +- Adding unminified CSS to dist output, fixes #506 (Gion Kunz) +- Refactored namespaced attribute handling, fixes #584 (Gion Kunz) +- Allow charts to be created without data and labels, fixes #598, fixes #588, fixes #537, fixes #425 (Gion Kunz> Date: Mon, 24 Oct 2016 01:01:08 +0200 Subject: [PATCH 453/593] Set down required node version to >=4.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2022f949..f11329e9 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "time-grunt": "^1.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=4.6.0" }, "scripts": { "start": "./node_modules/.bin/grunt", From 1c2b5dc55b33d92ed17a96d0bbe8f172f2221187 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Mon, 24 Oct 2016 01:01:44 +0200 Subject: [PATCH 454/593] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f11329e9..6748b1d2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.10.0", + "version": "0.10.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From b2e9b4eb111ad1730b2257d8176218e8eb02f0b6 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 25 Oct 2016 04:16:24 +0200 Subject: [PATCH 455/593] chore(testing): Refactored all tests to ES6 --- karma.ci.config.js | 1 + karma.watch.config.js | 1 + src/axes/auto-scale-axis.js | 2 +- src/axes/axis.js | 28 +- src/axes/axis.spec.js | 35 +- src/axes/fixed-scale-axis.js | 16 +- src/axes/fixed-scale-axis.spec.js | 49 ++- src/axes/step-axis.js | 2 +- src/axes/step-axis.spec.js | 40 +- src/charts/bar.js | 122 +++--- src/charts/bar.spec.js | 339 ++++++++++++++++ src/charts/base.js | 20 +- src/charts/line.js | 167 ++++---- src/charts/line.spec.js | 582 ++++++++++++++++++++++++++++ src/charts/pie.js | 72 ++-- src/charts/pie.spec.js | 442 +++++++++++++++++++++ src/core/creation.js | 92 +++-- src/core/creation.spec.js | 4 +- src/core/data.js | 137 +++---- src/core/data.spec.js | 4 +- src/core/extend.js | 13 +- src/core/functional.js | 66 +--- src/core/lang.js | 7 +- src/core/math.js | 10 +- src/core/options-provider.js | 36 +- src/event/event-emitter.js | 8 +- src/interpolation/cardinal.js | 37 +- src/interpolation/monotone-cubic.js | 40 +- src/interpolation/none.js | 16 +- src/interpolation/simple.js | 23 +- src/interpolation/step.js | 16 +- src/svg/svg-path.spec.js | 166 ++++++++ src/svg/svg.js | 64 ++- src/svg/svg.spec.js | 165 ++++++++ 34 files changed, 2228 insertions(+), 594 deletions(-) create mode 100644 src/charts/bar.spec.js create mode 100644 src/charts/line.spec.js create mode 100644 src/charts/pie.spec.js create mode 100644 src/svg/svg-path.spec.js create mode 100644 src/svg/svg.spec.js diff --git a/karma.ci.config.js b/karma.ci.config.js index 56a02843..e08d40b8 100644 --- a/karma.ci.config.js +++ b/karma.ci.config.js @@ -6,6 +6,7 @@ module.exports = function(config) { singleRun: true, browsers: ['PhantomJS'], files: [ + 'node_modules/core-js/client/shim.min.js', { pattern: 'src/**/*.+(js|html)', included: false }, { pattern: 'tooling/**/*.js', included: false }, { pattern: 'package.json', included: false }, diff --git a/karma.watch.config.js b/karma.watch.config.js index 95bb102d..9d42a362 100644 --- a/karma.watch.config.js +++ b/karma.watch.config.js @@ -6,6 +6,7 @@ module.exports = function(config) { browsers: ['PhantomJS'], reporters: ['nyan'], files: [ + 'node_modules/core-js/client/shim.min.js', { pattern: 'src/**/*.+(js|html)', included: false }, { pattern: 'tooling/**/*.js', included: false }, { pattern: 'package.json', included: false }, diff --git a/src/axes/auto-scale-axis.js b/src/axes/auto-scale-axis.js index f195c723..5d057dd5 100644 --- a/src/axes/auto-scale-axis.js +++ b/src/axes/auto-scale-axis.js @@ -5,7 +5,7 @@ export class AutoScaleAxis extends Axis { constructor(axisUnit, data, chartRect, options) { super(); // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options - var highLow = options.highLow || getHighLow(data, options, axisUnit.pos); + const highLow = options.highLow || getHighLow(data, options, axisUnit.pos); this.bounds = getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); this.range = { min: this.bounds.min, diff --git a/src/axes/axis.js b/src/axes/axis.js index 09caa859..09119ca2 100644 --- a/src/axes/axis.js +++ b/src/axes/axis.js @@ -36,19 +36,19 @@ export class Axis { } createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) { - var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; - var projectedValues = this.ticks.map(this.projectValue.bind(this)); - var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); + const axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; + const projectedValues = this.ticks.map(this.projectValue.bind(this)); + const labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); - projectedValues.forEach(function(projectedValue, index) { - var labelOffset = { + projectedValues.forEach((projectedValue, index) => { + const labelOffset = { x: 0, y: 0 }; // TODO: Find better solution for solving this problem // Calculate how much space we have available for the label - var labelLength; + let labelLength; if(projectedValues[index + 1]) { // If we still have one label ahead, we can calculate the distance to the next tick / label labelLength = projectedValues[index + 1] - projectedValue; @@ -59,7 +59,7 @@ export class Axis { labelLength = Math.max(this.axisLength - projectedValue, 30); } - // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + // Skip grid lines and labels where interpolated label values are falsey (except for 0) if(isFalseyButZero(labelValues[index]) && labelValues[index] !== '') { return; } @@ -73,9 +73,13 @@ export class Axis { // If the labels should be positioned in start position (top side for vertical axis) we need to set a // different offset as for positioned with end (bottom) if(chartOptions.axisX.position === 'start') { - labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + labelOffset.y = this.chartRect.padding.top + + chartOptions.axisX.labelOffset.y + + (useForeignObject ? 5 : 20); } else { - labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + labelOffset.y = this.chartRect.y1 + + chartOptions.axisX.labelOffset.y + + (useForeignObject ? 5 : 20); } } else { projectedValue = this.chartRect.y1 - projectedValue; @@ -84,7 +88,9 @@ export class Axis { // If the labels should be positioned in start position (left side for horizontal axis) we need to set a // different offset as for positioned with end (right side) if(chartOptions.axisY.position === 'start') { - labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10; + labelOffset.x = useForeignObject ? + this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : + this.chartRect.x1 - 10; } else { labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; } @@ -104,6 +110,6 @@ export class Axis { (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']) ], useForeignObject, eventEmitter); } - }.bind(this)); + }); } } diff --git a/src/axes/axis.spec.js b/src/axes/axis.spec.js index be55efcc..fd3b579c 100644 --- a/src/axes/axis.spec.js +++ b/src/axes/axis.spec.js @@ -2,10 +2,10 @@ import {Svg} from '../svg/svg'; import {EventEmitter} from '../event/event-emitter'; import {Axis, axisUnits} from './axis'; -describe('Axis', function() { - var ticks, chartRect, chartOptions, eventEmitter, gridGroup, labelGroup; +describe('Axis', () => { + let ticks, chartRect, chartOptions, eventEmitter, gridGroup, labelGroup; - beforeEach(function() { + beforeEach(() => { eventEmitter = new EventEmitter(); gridGroup = new Svg('g'); labelGroup = new Svg('g'); @@ -53,16 +53,13 @@ describe('Axis', function() { }; }); - it('should skip all grid lines and labels for interpolated value of null', function() { - chartOptions.axisX.labelInterpolationFnc = function(value, index) { - return index === 0 ? null : value; - }; + it('should skip all grid lines and labels for interpolated value of null', () => { + chartOptions.axisX.labelInterpolationFnc = + (value, index) => index === 0 ? null : value; var axis = new Axis(); axis.initialize(axisUnits.x, chartRect, ticks, null); - axis.projectValue = function(value) { - return value; - }; + axis.projectValue = (value) => value; axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(1); @@ -70,15 +67,12 @@ describe('Axis', function() { }); it('should skip all grid lines and labels for interpolated value of undefined', function() { - chartOptions.axisX.labelInterpolationFnc = function(value, index) { - return index === 0 ? undefined : value; - }; + chartOptions.axisX.labelInterpolationFnc = + (value, index) => index === 0 ? undefined : value; var axis = new Axis(); axis.initialize(axisUnits.x, chartRect, ticks, null); - axis.projectValue = function(value) { - return value; - }; + axis.projectValue = (value) => value; axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(1); @@ -86,15 +80,12 @@ describe('Axis', function() { }); it('should include all grid lines and labels for interpolated value of empty strings', function() { - chartOptions.axisX.labelInterpolationFnc = function(value, index) { - return index === 0 ? '' : value; - }; + chartOptions.axisX.labelInterpolationFnc = + (value, index) => index === 0 ? '' : value; var axis = new Axis(); axis.initialize(axisUnits.x, chartRect, ticks, null); - axis.projectValue = function(value) { - return value; - }; + axis.projectValue = (value) => value; axis.createGridAndLabels(gridGroup, labelGroup, true, chartOptions, eventEmitter); expect(gridGroup.querySelectorAll('.ct-grid').svgElements.length).toBe(2); diff --git a/src/axes/fixed-scale-axis.js b/src/axes/fixed-scale-axis.js index 117c94fb..9e0c59aa 100644 --- a/src/axes/fixed-scale-axis.js +++ b/src/axes/fixed-scale-axis.js @@ -6,14 +6,13 @@ export class FixedScaleAxis extends Axis { constructor(axisUnit, data, chartRect, options) { super(); - var highLow = options.highLow || getHighLow(data, options, axisUnit.pos); + const highLow = options.highLow || getHighLow(data, options, axisUnit.pos); this.divisor = options.divisor || 1; - this.ticks = options.ticks || times(this.divisor).map(function(value, index) { - return highLow.low + (highLow.high - highLow.low) / this.divisor * index; - }.bind(this)); - this.ticks.sort(function(a, b) { - return a - b; - }); + this.ticks = options.ticks || + times(this.divisor).map( + (value, index) => highLow.low + (highLow.high - highLow.low) / this.divisor * index + ); + this.ticks.sort((a, b) => a - b); this.range = { min: highLow.low, max: highLow.high @@ -25,6 +24,7 @@ export class FixedScaleAxis extends Axis { } projectValue(value) { - return this.axisLength * (+getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); + return this.axisLength * (+getMultiValue(value, this.units.pos) - this.range.min) / + (this.range.max - this.range.min); } } diff --git a/src/axes/fixed-scale-axis.spec.js b/src/axes/fixed-scale-axis.spec.js index 027cf42d..d1cbce6c 100644 --- a/src/axes/fixed-scale-axis.spec.js +++ b/src/axes/fixed-scale-axis.spec.js @@ -1,9 +1,9 @@ import {FixedScaleAxis} from './fixed-scale-axis'; -describe('FixedScaleAxis', function () { - it('should order the tick array', function () { - var ticks = [10, 5, 0, -5, -10]; - var axisUnit = { +describe('FixedScaleAxis', () => { + it('should order the tick array', () => { + const ticks = [10, 5, 0, -5, -10]; + const axisUnit = { pos: 'y', len: 'height', dir: 'vertical', @@ -11,25 +11,32 @@ describe('FixedScaleAxis', function () { rectEnd: 'y1', rectOffset: 'x1' }; - var data = [[{x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5}]]; - var chartRect = { - 'padding': {'top': 15, 'right': 15, 'bottom': 5, 'left': 10}, - 'y2': 15, - 'y1': 141, - 'x1': 50, - 'x2': 269 + const data = [ + [{x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5}] + ]; + const chartRect = { + padding: { + top: 15, + right: 15, + bottom: 5, + left: 10 + }, + y2: 15, + y1: 141, + x1: 50, + x2: 269 }; - var options = { - 'offset': 40, - 'position': 'start', - 'labelOffset': {'x': 0, 'y': 0}, - 'showLabel': true, - 'showGrid': true, - 'scaleMinSpace': 20, - 'onlyInteger': false, - 'ticks': ticks + const options = { + offset: 40, + position: 'start', + labelOffset: {'x': 0, 'y': 0}, + showLabel: true, + showGrid: true, + scaleMinSpace: 20, + onlyInteger: false, + ticks }; - var fsaxis = new FixedScaleAxis(axisUnit, data, chartRect, options); + const fsaxis = new FixedScaleAxis(axisUnit, data, chartRect, options); expect(fsaxis.ticks).toEqual([-10, -5, 0, 5, 10]); }); }); diff --git a/src/axes/step-axis.js b/src/axes/step-axis.js index dbbd984a..8010e33c 100644 --- a/src/axes/step-axis.js +++ b/src/axes/step-axis.js @@ -5,7 +5,7 @@ export class StepAxis extends Axis { super(); super.initialize(axisUnit, chartRect, options.ticks, options); - var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0)); + const calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0)); this.stepLength = this.axisLength / calc; } diff --git a/src/axes/step-axis.spec.js b/src/axes/step-axis.spec.js index bf09501b..85de78e4 100644 --- a/src/axes/step-axis.spec.js +++ b/src/axes/step-axis.spec.js @@ -2,26 +2,26 @@ import {StepAxis} from './step-axis'; describe('StepAxis', function() { it('should return 0 if options.ticks.length == 1', function() { - var ticks = [1], - axisUnit = { - 'pos':'y', - 'len':'height', - 'dir':'vertical', - 'rectStart':'y2', - 'rectEnd':'y1', - 'rectOffset':'x1' - }, - data = [[1]], - chartRect = { - 'y2':0, - 'y1':15, - 'x1':50, - 'x2':100 - }, - options = { - 'ticks': ticks - }, - stepAxis = new StepAxis(axisUnit, data, chartRect, options); + const ticks = [1]; + const axisUnit = { + pos: 'y', + len: 'height', + dir: 'vertical', + rectStart: 'y2', + rectEnd: 'y1', + rectOffset: 'x1' + }; + const data = [[1]]; + const chartRect = { + y2: 0, + y1: 15, + x1: 50, + x2: 100 + }; + const options = { + ticks + }; + const stepAxis = new StepAxis(axisUnit, data, chartRect, options); expect(stepAxis.stepLength).toEqual(15); }); }); diff --git a/src/charts/bar.js b/src/charts/bar.js index 1a88605c..2525abc1 100644 --- a/src/charts/bar.js +++ b/src/charts/bar.js @@ -153,14 +153,12 @@ export class BarChart extends BaseChart { * */ createChart(options) { - var data; - var highLow; + let data; + let highLow; if(options.distributeSeries) { data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); - data.normalized.series = data.normalized.series.map(function(value) { - return [value]; - }); + data.normalized.series = data.normalized.series.map((value) => [value]); } else { data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); } @@ -174,28 +172,26 @@ export class BarChart extends BaseChart { ); // Drawing groups in correct order - var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); - var seriesGroup = this.svg.elem('g'); - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + const gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + const seriesGroup = this.svg.elem('g'); + const labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); if(options.stackBars && data.normalized.series.length !== 0) { - // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = serialMap(data.normalized.series, function serialSums() { - return Array.prototype.slice.call(arguments).map(function(value) { - return value; - }).reduce(function(prev, curr) { - return { - x: prev.x + (curr && curr.x) || 0, - y: prev.y + (curr && curr.y) || 0 - }; - }, {x: 0, y: 0}); - }); + var serialSums = serialMap(data.normalized.series, () => + Array.from(arguments) + .map((value) => value) + .reduce((prev, curr) => { + return { + x: prev.x + (curr && curr.x) || 0, + y: prev.y + (curr && curr.y) || 0 + }; + }, {x: 0, y: 0}) + ); highLow = getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y'); } else { - highLow = getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y'); } @@ -203,13 +199,12 @@ export class BarChart extends BaseChart { highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); - var chartRect = createChartRect(this.svg, options, defaultOptions.padding); - - var valueAxis, - labelAxisTicks, - labelAxis, - axisX, - axisY; + const chartRect = createChartRect(this.svg, options, defaultOptions.padding); + let valueAxis; + let labelAxisTicks; + let labelAxis; + let axisX; + let axisY; // We need to set step count based on some options combinations if(options.distributeSeries && options.stackBars) { @@ -259,7 +254,7 @@ export class BarChart extends BaseChart { referenceValue: 0 })); } else { - valueAxis = axisY = new options.axisY.type(axisUnits.units.y, data.normalized.series, chartRect, extend({}, options.axisY, { + valueAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); @@ -267,9 +262,11 @@ export class BarChart extends BaseChart { } // Projected 0 point - var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0)); + const zeroPoint = options.horizontalBars ? + (chartRect.x1 + valueAxis.projectValue(0)) : + (chartRect.y1 - valueAxis.projectValue(0)); // Used to track the screen coordinates of stacked bars - var stackedBarValues = []; + const stackedBarValues = []; labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); @@ -279,13 +276,11 @@ export class BarChart extends BaseChart { } // Draw the series - data.raw.series.forEach(function(series, seriesIndex) { + data.raw.series.forEach((series, seriesIndex) => { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. - var biPol = seriesIndex - (data.raw.series.length - 1) / 2; + const biPol = seriesIndex - (data.raw.series.length - 1) / 2; // Half of the period width between vertical grid lines used to position bars - var periodHalfLength; - // Current series SVG element - var seriesElement; + let periodHalfLength; // We need to set periodHalfLength based on some options combinations if(options.distributeSeries && !options.stackBars) { @@ -302,7 +297,7 @@ export class BarChart extends BaseChart { } // Adding the series group to the series element - seriesElement = seriesGroup.elem('g'); + const seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ @@ -313,15 +308,11 @@ export class BarChart extends BaseChart { // Use series class from series data or if not set generate one seriesElement.addClass([ options.classNames.series, - (series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)) + series.className || `${options.classNames.series}-${alphaNumerate(seriesIndex)}` ].join(' ')); - data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { - var projected, - bar, - previousStack, - labelAxisValueIndex; - + data.normalized.series[seriesIndex].forEach((value, valueIndex) => { + let labelAxisValueIndex; // We need to set labelAxisValueIndex based on some options combinations if(options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection @@ -336,6 +327,7 @@ export class BarChart extends BaseChart { labelAxisValueIndex = valueIndex; } + let projected; // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { @@ -363,7 +355,7 @@ export class BarChart extends BaseChart { } // Enter value in stacked bar values used to remember previous screen value for stacking up bars - previousStack = stackedBarValues[valueIndex] || zeroPoint; + const previousStack = stackedBarValues[valueIndex] || zeroPoint; stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); // Skip if value is undefined @@ -371,22 +363,22 @@ export class BarChart extends BaseChart { return; } - var positions = {}; - positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; - positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; + const positions = {}; + positions[`${labelAxis.units.pos}1`] = projected[labelAxis.units.pos]; + positions[`${labelAxis.units.pos}2`] = projected[labelAxis.units.pos]; if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) { // Stack mode: accumulate (default) // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line // We want backwards compatibility, so the expected fallback without the 'stackMode' option // to be the original behaviour (accumulate) - positions[labelAxis.counterUnits.pos + '1'] = previousStack; - positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; + positions[`${labelAxis.counterUnits.pos}1`] = previousStack; + positions[`${labelAxis.counterUnits.pos}2`] = stackedBarValues[valueIndex]; } else { // Draw from the zero line normally // This is also the same code for Stack mode: overlap - positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; - positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; + positions[`${labelAxis.counterUnits.pos}1`] = zeroPoint; + positions[`${labelAxis.counterUnits.pos}2`] = projected[labelAxis.counterUnits.pos]; } // Limit x and y so that they are within the chart rect @@ -395,37 +387,37 @@ export class BarChart extends BaseChart { positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); - var metaData = getMetaData(series, valueIndex); + const metaData = getMetaData(series, valueIndex); // Create bar element - bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ + const bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'ct:value': [value.x, value.y].filter(isNumeric).join(','), 'ct:meta': serialize(metaData) }); this.eventEmitter.emit('draw', extend({ type: 'bar', - value: value, + value, index: valueIndex, meta: metaData, - series: series, - seriesIndex: seriesIndex, - axisX: axisX, - axisY: axisY, - chartRect: chartRect, + series, + seriesIndex, + axisX, + axisY, + chartRect, group: seriesElement, element: bar }, positions)); - }.bind(this)); - }.bind(this)); + }); + }); this.eventEmitter.emit('created', { bounds: valueAxis.bounds, - chartRect: chartRect, - axisX: axisX, - axisY: axisY, + chartRect, + axisX, + axisY, svg: this.svg, - options: options + options }); } } diff --git a/src/charts/bar.spec.js b/src/charts/bar.spec.js new file mode 100644 index 00000000..133c8459 --- /dev/null +++ b/src/charts/bar.spec.js @@ -0,0 +1,339 @@ +import {AutoScaleAxis} from '../axes/axes'; +import {BarChart} from './bar'; +import {namespaces} from '../core/globals'; +import {deserialize} from '../core/data'; +import {addFixture, destroyFixtures, initializeFixtures} from '../testing/fixtures'; + +describe('BarChart', () => { + let fixture; + let options; + let data; + + function createChart(callback) { + fixture = addFixture('
    '); + const chart = new BarChart(fixture.wrapper.querySelector('.ct-chart'), data, options) + .on('created', () => { + callback && callback(); + chart.off('created'); + }); + return chart; + } + + beforeEach(() => initializeFixtures()); + afterEach(() => { + destroyFixtures(); + data = undefined; + options = undefined; + }); + + describe('grids', () => { + beforeEach(() => { + data = { + series: [[ + { x: 1, y: 1 }, + { x: 3, y: 5 } + ]] + }; + options = { + axisX: { + type: AutoScaleAxis, + onlyInteger: true + }, + axisY: { + type: AutoScaleAxis, + onlyInteger: true + } + }; + }); + + it('should contain ct-grids group', (done) => { + data = null; + options = null; + createChart(() => { + expect(fixture.wrapper.querySelectorAll('g.ct-grids').length).toBe(1); + done(); + }); + }); + + it('should draw grid lines', (done) => { + createChart(() => { + expect(fixture.wrapper.querySelectorAll('g.ct-grids line.ct-grid.ct-horizontal').length).toBe(3); + expect(fixture.wrapper.querySelectorAll('g.ct-grids line.ct-grid.ct-vertical').length).toBe(6); + done(); + }); + }); + + it('should draw grid background', (done) => { + options.showGridBackground = true; + createChart(() => { + expect(fixture.wrapper.querySelectorAll('g.ct-grids rect.ct-grid-background').length).toBe(1); + done(); + }); + }); + + it('should not draw grid background if option set to false', (done) => { + options.showGridBackground = false; + createChart(() => { + expect(fixture.wrapper.querySelectorAll('g.ct-grids rect.ct-grid-background').length).toBe(0); + done(); + }); + }); + + }); + + describe('ct:value attribute', () => { + it('should contain x and y value for each bar', (done) => { + data = { + series: [[ + {x: 1, y: 2}, + {x: 3, y: 4} + ]] + }; + options = { + axisX: { + type: AutoScaleAxis + } + }; + + createChart(() => { + const bars = fixture.wrapper.querySelectorAll('.ct-bar'); + expect(bars[0].getAttributeNS(namespaces.ct, 'value')).toEqual('1,2'); + expect(bars[1].getAttributeNS(namespaces.ct, 'value')).toEqual('3,4'); + done(); + }); + }); + + it('should render values that are zero', (done) => { + data = { + series: [[ + {x: 0, y: 1}, + {x: 2, y: 0}, + {x: 0, y: 0} + ]] + }; + options = { + axisX: { + type: AutoScaleAxis + } + }; + + createChart(() => { + const bars = fixture.wrapper.querySelectorAll('.ct-bar'); + expect(bars[0].getAttributeNS(namespaces.ct, 'value')).toEqual('0,1'); + expect(bars[1].getAttributeNS(namespaces.ct, 'value')).toEqual('2,0'); + expect(bars[2].getAttributeNS(namespaces.ct, 'value')).toEqual('0,0'); + done(); + }); + }); + }); + + describe('Meta data tests', () => { + it('should render meta data correctly with mixed value array', (done) => { + const meta = { + test: 'Serialized Test' + }; + + data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + createChart(() => { + const bar = fixture.wrapper.querySelectorAll('.ct-bar')[3]; + expect(deserialize(bar.getAttributeNS(namespaces.ct, 'meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and different normalized data length', (done) => { + const meta = { + test: 'Serialized Test' + }; + + data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + createChart(() => { + const bar = fixture.wrapper.querySelectorAll('.ct-bar')[3]; + expect(deserialize(bar.getAttributeNS(namespaces.ct, 'meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and mixed series notation', (done) => { + const seriesMeta = 9999; + const valueMeta = { + test: 'Serialized Test' + }; + + data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: valueMeta + }, 0], + { + meta: seriesMeta, + data: [5, 2, { + value: 2, + meta: valueMeta + }, 0] + } + ] + }; + + createChart(() => { + expect( + deserialize( + fixture.wrapper.querySelectorAll('.ct-series-a .ct-bar')[3] + .getAttributeNS(namespaces.ct, 'meta') + ) + ).toEqual(valueMeta); + + expect( + deserialize( + fixture.wrapper.querySelector('.ct-series-b') + .getAttributeNS(namespaces.ct, 'meta') + ) + ).toEqual(seriesMeta); + + expect( + deserialize( + fixture.wrapper.querySelectorAll('.ct-series-b .ct-bar')[2] + .getAttributeNS(namespaces.ct, 'meta') + ) + ).toEqual(valueMeta); + + done(); + }); + }); + }); + + describe('Empty data tests', () => { + it('should render empty grid with no data', (done) => { + data = null; + options = null; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with only labels', (done) => { + data = { + labels: [1, 2, 3, 4] + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Find exactly as many horizontal grid lines as labels were specified (Step Axis) + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(data.labels.length); + done(); + }); + }); + + it('should generate labels and render empty grid with only series in data', (done) => { + data = { + series: [ + [1, 2, 3, 4], + [2, 3, 4], + [3, 4] + ] + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Should generate the labels using the largest series count + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length) + .toBe(Math.max(...data.series.map((series) => series.length))); + done(); + }); + }); + + it('should render empty grid with no data and specified high low', (done) => { + options = { + width: 400, + height: 300, + high: 100, + low: -100 + }; + + createChart(() => { + // Find first and last label + const labels = document.querySelectorAll('.ct-labels .ct-label.ct-vertical'); + const firstLabel = labels[0]; + const lastLabel = labels[labels.length - 1]; + + expect(firstLabel.textContent.trim()).toBe('-100'); + expect(lastLabel.textContent.trim()).toBe('100'); + done(); + }); + }); + + it('should render empty grid with no data and reverseData option', (done) => { + options = { + reverseData: true + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and stackBars option', (done) => { + options = { + stackBars: true + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and horizontalBars option', (done) => { + options = { + horizontalBars: true + }; + + createChart(() => { + // Find at least one vertical grid line + // TODO: In theory the axis should be created with ct-horizontal class + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with no data and distributeSeries option', (done) => { + options = { + distributeSeries: true + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + }); +}); diff --git a/src/charts/base.js b/src/charts/base.js index 4b2a8e0e..b9170606 100644 --- a/src/charts/base.js +++ b/src/charts/base.js @@ -24,22 +24,20 @@ export class BaseChart { this.eventEmitter = new EventEmitter(); this.supportsForeignObject = isSupported('Extensibility'); this.supportsAnimations = isSupported('AnimationEventsAttribute'); - this.resizeListener = function resizeListener(){ - this.update(); - }.bind(this); - + this.resizeListener = () => this.update(); + if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { this.container.__chartist__.detach(); } - + this.container.__chartist__ = this; } - + // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. - this.initializeTimeoutId = setTimeout(this.initialize.bind(this), 0); + this.initializeTimeoutId = setTimeout(() => this.initialize(), 0); } createChart() { @@ -142,20 +140,18 @@ export class BaseChart { // This will also register a listener that is re-creating the chart based on media changes this.optionsProvider = optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); // Register options change listener that will trigger a chart update - this.eventEmitter.addEventHandler('optionsChanged', function() { - this.update(); - }.bind(this)); + this.eventEmitter.addEventHandler('optionsChanged', () => this.update()); // Before the first chart creation we need to register us with all plugins that are configured // Initialize all relevant plugins with our chart object and the plugin options specified in the config if(this.options.plugins) { - this.options.plugins.forEach(function(plugin) { + this.options.plugins.forEach((plugin) => { if(plugin instanceof Array) { plugin[0](this, plugin[1]); } else { plugin(this); } - }.bind(this)); + }); } // Event for data transformation that allows to manipulate the data before it gets rendered in the charts diff --git a/src/charts/line.js b/src/charts/line.js index 83ada68f..caf498ff 100644 --- a/src/charts/line.js +++ b/src/charts/line.js @@ -198,19 +198,20 @@ export class LineChart extends BaseChart { * */ createChart(options) { - var data = normalizeData(this.data, options.reverseData, true); + const data = normalizeData(this.data, options.reverseData, true); // Create new svg object this.svg = createSvg(this.container, options.width, options.height, options.classNames.chart); // Create groups for labels, grid and series - var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); - var seriesGroup = this.svg.elem('g'); - var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); + const gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); + const seriesGroup = this.svg.elem('g'); + const labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); - var chartRect = createChartRect(this.svg, options, defaultOptions.padding); - var axisX, axisY; + const chartRect = createChartRect(this.svg, options, defaultOptions.padding); + let axisX; + let axisY; - if(options.axisX.type === undefined) { + if (options.axisX.type === undefined) { axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { ticks: data.normalized.labels, stretch: options.fullWidth @@ -219,7 +220,7 @@ export class LineChart extends BaseChart { axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX); } - if(options.axisY.type === undefined) { + if (options.axisY.type === undefined) { axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { high: isNumeric(options.high) ? options.high : options.axisY.high, low: isNumeric(options.low) ? options.low : options.axisY.low @@ -236,8 +237,8 @@ export class LineChart extends BaseChart { } // Draw the series - data.raw.series.forEach(function(series, seriesIndex) { - var seriesElement = seriesGroup.elem('g'); + data.raw.series.forEach((series, seriesIndex) => { + const seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ @@ -248,26 +249,26 @@ export class LineChart extends BaseChart { // Use series class from series data or if not set generate one seriesElement.addClass([ options.classNames.series, - (series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)) + series.className || `${options.classNames.series}-${alphaNumerate(seriesIndex)}` ].join(' ')); - var pathCoordinates = [], - pathData = []; + const pathCoordinates = []; + const pathData = []; - data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { - var p = { + data.normalized.series[seriesIndex].forEach((value, valueIndex) => { + const p = { x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]), y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex]) }; pathCoordinates.push(p.x, p.y); pathData.push({ - value: value, - valueIndex: valueIndex, + value, + valueIndex, meta: getMetaData(series, valueIndex) }); - }.bind(this)); + }); - var seriesOptions = { + const seriesOptions = { lineSmooth: getSeriesOption(series, options, 'lineSmooth'), showPoint: getSeriesOption(series, options, 'showPoint'), showLine: getSeriesOption(series, options, 'showLine'), @@ -275,19 +276,19 @@ export class LineChart extends BaseChart { areaBase: getSeriesOption(series, options, 'areaBase') }; - var smoothing = typeof seriesOptions.lineSmooth === 'function' ? + const smoothing = typeof seriesOptions.lineSmooth === 'function' ? seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? monotoneCubic() : none()); // Interpolating path where pathData will be used to annotate each path element so we can trace back the original // index, value and meta data - var path = smoothing(pathCoordinates, pathData); + const path = smoothing(pathCoordinates, pathData); // If we should show points we need to create them now to avoid secondary loop // Points are drawn from the pathElements returned by the interpolation function // Small offset for Firefox to render squares correctly if (seriesOptions.showPoint) { - path.pathElements.forEach(function(pathElement) { - var point = seriesElement.elem('line', { + path.pathElements.forEach((pathElement) => { + const point = seriesElement.elem('line', { x1: pathElement.x, y1: pathElement.y, x2: pathElement.x + 0.01, @@ -302,20 +303,20 @@ export class LineChart extends BaseChart { value: pathElement.data.value, index: pathElement.data.valueIndex, meta: pathElement.data.meta, - series: series, - seriesIndex: seriesIndex, - axisX: axisX, - axisY: axisY, + series, + seriesIndex, + axisX, + axisY, group: seriesElement, element: point, x: pathElement.x, y: pathElement.y }); - }.bind(this)); + }); } - if(seriesOptions.showLine) { - var line = seriesElement.elem('path', { + if (seriesOptions.showLine) { + const line = seriesElement.elem('path', { d: path.stringify() }, options.classNames.line, true); @@ -323,80 +324,84 @@ export class LineChart extends BaseChart { type: 'line', values: data.normalized.series[seriesIndex], path: path.clone(), - chartRect: chartRect, + chartRect, + // TODO: Remove redundant index: seriesIndex, - series: series, - seriesIndex: seriesIndex, + series, + seriesIndex, seriesMeta: series.meta, - axisX: axisX, - axisY: axisY, + axisX, + axisY, group: seriesElement, element: line }); } // Area currently only works with axes that support a range! - if(seriesOptions.showArea && axisY.range) { + if (seriesOptions.showArea && axisY.range) { // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); + const areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); // We project the areaBase value into screen coordinates - var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); + const areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); // In order to form the area we'll first split the path by move commands so we can chunk it up into segments - path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { + path.splitByCommand('M') // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area - return pathSegment.pathElements.length > 1; - }).map(function convertToArea(solidPathSegments) { - // Receiving the filtered solid path segments we can now convert those segments into fill areas - var firstElement = solidPathSegments.pathElements[0]; - var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; + .filter((pathSegment) => pathSegment.pathElements.length > 1) + .map((solidPathSegments) => { + // Receiving the filtered solid path segments we can now convert those segments into fill areas + const firstElement = solidPathSegments.pathElements[0]; + const lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; - // Cloning the solid path segment with closing option and removing the first move command from the clone - // We then insert a new move that should start at the area base and draw a straight line up or down - // at the end of the path we add an additional straight line to the projected area base value - // As the closing option is set our path will be automatically closed - return solidPathSegments.clone(true) - .position(0) - .remove(1) - .move(firstElement.x, areaBaseProjected) - .line(firstElement.x, firstElement.y) - .position(solidPathSegments.pathElements.length + 1) - .line(lastElement.x, areaBaseProjected); + // Cloning the solid path segment with closing option and removing the first move command from the clone + // We then insert a new move that should start at the area base and draw a straight line up or down + // at the end of the path we add an additional straight line to the projected area base value + // As the closing option is set our path will be automatically closed + return solidPathSegments.clone(true) + .position(0) + .remove(1) + .move(firstElement.x, areaBaseProjected) + .line(firstElement.x, firstElement.y) + .position(solidPathSegments.pathElements.length + 1) + .line(lastElement.x, areaBaseProjected); - }).forEach(function createArea(areaPath) { - // For each of our newly created area paths, we'll now create path elements by stringifying our path objects - // and adding the created DOM elements to the correct series group - var area = seriesElement.elem('path', { - d: areaPath.stringify() - }, options.classNames.area, true); + }) + .forEach((areaPath) => { + // For each of our newly created area paths, we'll now create path elements by stringifying our path objects + // and adding the created DOM elements to the correct series group + const area = seriesElement.elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true); - // Emit an event for each area that was drawn - this.eventEmitter.emit('draw', { - type: 'area', - values: data.normalized.series[seriesIndex], - path: areaPath.clone(), - series: series, - seriesIndex: seriesIndex, - axisX: axisX, - axisY: axisY, - chartRect: chartRect, - index: seriesIndex, - group: seriesElement, - element: area + // Emit an event for each area that was drawn + this.eventEmitter.emit('draw', { + type: 'area', + values: data.normalized.series[seriesIndex], + path: areaPath.clone(), + series, + seriesIndex, + axisX, + axisY, + chartRect, + // TODO: Remove redundant + index: seriesIndex, + group: seriesElement, + element: area + }); }); - }.bind(this)); } - }.bind(this)); - + }); + this.eventEmitter.emit('created', { + // TODO: Remove redundant bounds: axisY.bounds, - chartRect: chartRect, - axisX: axisX, - axisY: axisY, + chartRect, + axisX, + axisY, svg: this.svg, - options: options + options }); } } diff --git a/src/charts/line.spec.js b/src/charts/line.spec.js new file mode 100644 index 00000000..00435294 --- /dev/null +++ b/src/charts/line.spec.js @@ -0,0 +1,582 @@ +import {AutoScaleAxis, FixedScaleAxis} from '../axes/axes'; +import {LineChart} from './line'; +import * as Interpolation from '../interpolation/interpolation'; +import {namespaces} from '../core/globals'; +import {deserialize} from '../core/data'; +import {addFixture, destroyFixtures, initializeFixtures} from '../testing/fixtures'; + +describe('LineChart', () => { + let fixture; + let options; + let data; + + function createChart(callback) { + fixture = addFixture('
    '); + const chart = new LineChart(fixture.wrapper.querySelector('.ct-chart'), data, options) + .on('created', () => { + callback && callback(); + chart.off('created'); + }); + return chart; + } + + beforeEach(() => initializeFixtures()); + afterEach(() => { + destroyFixtures(); + data = undefined; + options = undefined; + }); + + describe('grids', () => { + beforeEach(() => { + data = { + series: [[ + { x: 1, y: 1 }, + { x: 3, y: 5 } + ]] + }; + options = { + axisX: { + type: AutoScaleAxis, + onlyInteger: true + }, + axisY: { + type: AutoScaleAxis, + onlyInteger: true + } + }; + }); + + it('should contain ct-grids group', (done) => { + createChart(() => { + expect(fixture.wrapper.querySelectorAll('.ct-grids').length).toBe(1); + done(); + }); + }); + + it('should draw grid lines', (done) => { + createChart(() => { + expect(fixture.wrapper.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(3); + expect(fixture.wrapper.querySelectorAll('.ct-grids .ct-grid.ct-vertical').length).toBe(5); + done(); + }); + }); + + it('should draw grid background', (done) => { + options.showGridBackground = true; + createChart(() => { + expect(fixture.wrapper.querySelectorAll('.ct-grids .ct-grid-background').length).toBe(1); + done(); + }); + }); + + it('should not draw grid background if option set to false', (done) => { + options.showGridBackground = false; + createChart(() => { + expect(fixture.wrapper.querySelectorAll('.ct-grids .ct-grid-background').length).toBe(0); + done(); + }); + }); + }); + + describe('AxisY position tests', () => { + beforeEach(() => { + data = { + series: [[ + { x: 1, y: 1 }, + { x: 3, y: 5 } + ]] + }; + options = {}; + }); + + it('should have ct-start class if position start', (done) => { + options = { + axisY: { + position: 'start' + } + }; + + createChart(() => { + Array.from(fixture.wrapper.querySelectorAll('.ct-label.ct-vertical')) + .forEach((element) => expect(element.getAttribute('class')).toBe('ct-label ct-vertical ct-start')); + done(); + }); + }); + + it('should have ct-end class if position is any other value than start', (done) => { + options = { + axisY: { + position: 'right' + } + }; + + createChart(() => { + Array.from(fixture.wrapper.querySelectorAll('.ct-label.ct-vertical')) + .forEach((element) => expect(element.getAttribute('class')).toBe('ct-label ct-vertical ct-end')); + done(); + }); + }); + }); + + describe('ct:value attribute', () => { + it('should contain x and y value for each datapoint', (done) => { + data = { + series: [[ + {x: 1, y: 2}, + {x: 3, y: 4} + ]] + }; + options = { + axisX: { + type: FixedScaleAxis + } + }; + + createChart(() => { + const points = fixture.wrapper.querySelectorAll('.ct-point'); + expect(points[0].getAttributeNS(namespaces.ct, 'value')).toBe('1,2'); + expect(points[1].getAttributeNS(namespaces.ct, 'value')).toBe('3,4'); + done(); + }); + }); + + it('should render values that are zero', (done) => { + data = { + series: [[ + {x: 0, y: 1}, + {x: 1, y: 0}, + {x: 0, y: 0} + ]] + }; + options = { + axisX: { + type: FixedScaleAxis + } + }; + + createChart(() => { + const points = fixture.wrapper.querySelectorAll('.ct-point'); + expect(points[0].getAttributeNS(namespaces.ct, 'value')).toBe('0,1'); + expect(points[1].getAttributeNS(namespaces.ct, 'value')).toBe('1,0'); + expect(points[2].getAttributeNS(namespaces.ct, 'value')).toBe('0,0'); + done(); + }); + }); + }); + + describe('Meta data tests', () => { + it('should render meta data correctly with mixed value array', (done) => { + const meta = { + test: 'Serialized Test' + }; + + data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + createChart(() => { + const points = fixture.wrapper.querySelectorAll('.ct-point'); + expect(deserialize(points[3].getAttributeNS(namespaces.ct, 'meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and different normalized data length', (done) => { + const meta = { + test: 'Serialized Test' + }; + + data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: meta + }, 0] + ] + }; + + createChart(() => { + const points = fixture.wrapper.querySelectorAll('.ct-point'); + expect(deserialize(points[3].getAttributeNS(namespaces.ct, 'meta'))).toEqual(meta); + done(); + }); + }); + + it('should render meta data correctly with mixed value array and mixed series notation', (done) => { + const seriesMeta = 9999; + const valueMeta = { + test: 'Serialized Test' + }; + + data = { + labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + series: [ + [5, 2, 4, { + value: 2, + meta: valueMeta + }, 0], + { + meta: seriesMeta, + data: [5, 2, { + value: 2, + meta: valueMeta + }, 0] + } + ] + }; + + createChart(() => { + expect( + deserialize( + fixture.wrapper.querySelectorAll('.ct-series-a .ct-point')[3] + .getAttributeNS(namespaces.ct, 'meta') + ) + ).toEqual(valueMeta); + + expect( + deserialize( + fixture.wrapper.querySelector('.ct-series-b') + .getAttributeNS(namespaces.ct, 'meta') + ) + ).toEqual(seriesMeta); + + expect( + deserialize( + fixture.wrapper.querySelectorAll('.ct-series-b .ct-point')[2] + .getAttributeNS(namespaces.ct, 'meta') + ) + ).toEqual(valueMeta); + + done(); + }); + }); + }); + + describe('Line charts with holes', () => { + it('should render correctly with Interpolation.none and holes everywhere', (done) => { + data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }; + options = { + lineSmooth: false + }; + + const chart = createChart(); + chart.on('draw', (context) => { + if (context.type === 'line') { + expect(context.path.pathElements.map((pathElement) => { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with Interpolation.cardinal and holes everywhere', (done) => { + data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }; + options = { + lineSmooth: true + }; + + const chart = createChart(); + chart.on('draw', (context) => { + if (context.type === 'line') { + expect(context.path.pathElements.map((pathElement) => { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + // Cardinal should create Line path segment if only one connection + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + // Cardinal should create Curve path segment for 2 or more connections + {command: 'C', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with Interpolation.monotoneCubic and holes everywhere', (done) => { + data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }; + options = { + lineSmooth: Interpolation.monotoneCubic() + }; + + const chart = createChart(); + chart.on('draw', (context) => { + if (context.type === 'line') { + expect(context.path.pathElements.map((pathElement) => { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + // Monotone cubic should create Line path segment if only one connection + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + // Monotone cubic should create Curve path segment for 2 or more connections + {command: 'C', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with Interpolation.simple and holes everywhere', (done) => { + data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }; + options = { + lineSmooth: Interpolation.simple() + }; + + const chart = createChart(); + chart.on('draw', (context) => { + if (context.type === 'line') { + expect(context.path.pathElements.map((pathElement) => { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'C', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'C', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'C', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with postponed Interpolation.step and holes everywhere', (done) => { + data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }; + options = { + lineSmooth: Interpolation.step() + }; + + const chart = createChart(); + chart.on('draw', (context) => { + if (context.type === 'line') { + expect(context.path.pathElements.map((pathElement) => { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} + ]); + done(); + } + }); + }); + + it('should render correctly with preponed Interpolation.step and holes everywhere', (done) => { + data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + series: [ + [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] + ] + }; + options ={ + lineSmooth: Interpolation.step({ + postpone: false + }) + }; + + const chart = createChart(); + chart.on('draw', (context) => { + if (context.type === 'line') { + expect(context.path.pathElements.map((pathElement) => { + return { + command: pathElement.command, + data: pathElement.data + }; + })).toEqual([ + {command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}}, + {command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'L', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}}, + {command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}} + ]); + done(); + } + }); + }); + }); + + describe('Single value data tests', () => { + beforeEach(() => { + data = { + labels: [1], + series: [[1]] + }; + }); + + it('should render without NaN values and points', (done) => { + createChart(() => { + expect(document.querySelector('.ct-line').getAttribute('d')).toBe('M50,15'); + expect(document.querySelector('.ct-point').getAttribute('x1')).toBe('50'); + expect(document.querySelector('.ct-point').getAttribute('x2')).toBe('50.01'); + done(); + }); + }); + }); + + describe('Empty data tests', () => { + it('should render empty grid with no data', (done) => { + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + + it('should render empty grid with only labels', (done) => { + data = { + labels: [1, 2, 3, 4] + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Find exactly as many horizontal grid lines as labels were specified (Step Axis) + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length).toBe(data.labels.length); + done(); + }); + }); + + it('should generate labels and render empty grid with only series in data', (done) => { + data = { + series: [ + [1, 2, 3, 4], + [2, 3, 4], + [3, 4] + ] + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + // Should generate the labels using the largest series count + expect(document.querySelectorAll('.ct-grids .ct-grid.ct-horizontal').length) + .toBe(Math.max(...data.series.map((series) => series.length))); + done(); + }); + }); + + it('should render empty grid with no data and specified high low', (done) => { + data = null; + options ={ + width: 400, + height: 300, + high: 100, + low: -100 + }; + + createChart(() => { + // Find first and last label + const labels = document.querySelectorAll('.ct-labels .ct-label.ct-vertical'); + const firstLabel = labels[0]; + const lastLabel = labels[labels.length - 1]; + + expect(firstLabel.textContent.trim()).toBe('-100'); + expect(lastLabel.textContent.trim()).toBe('100'); + done(); + }); + }); + + it('should render empty grid with no data and reverseData option', (done) => { + data = null; + options = { + reverseData: true + }; + + createChart(() => { + // Find at least one vertical grid line + expect(document.querySelector('.ct-grids .ct-grid.ct-vertical')).toBeDefined(); + done(); + }); + }); + }); + + describe('x1 and x2 attribute', () => { + it('should contain just a datapoint', (done) => { + data = { + series: [[ + {x: 1, y: 2} + ]] + }; + options = { + fullWidth: true + }; + + createChart(() => { + expect(document.querySelector('.ct-point').getAttribute('x1')).not.toBe('NaN'); + expect(document.querySelector('.ct-point').getAttribute('x2')).not.toBe('NaN'); + done(); + }); + }); + }); +}); diff --git a/src/charts/pie.js b/src/charts/pie.js index b8a7e0bb..ee0089e5 100644 --- a/src/charts/pie.js +++ b/src/charts/pie.js @@ -1,5 +1,5 @@ import {alphaNumerate, quantity, isFalseyButZero} from '../core/lang'; -import {noop} from '../core/functional'; +import {noop, sum} from '../core/functional'; import {polarToCartesian} from '../core/math'; import {extend} from '../core/extend'; import {normalizeData, serialize} from '../core/data'; @@ -62,7 +62,7 @@ const defaultOptions = { * @return {string} */ export function determineAnchorPosition(center, label, direction) { - var toTheRight = label.x > center.x; + const toTheRight = label.x > center.x; if (toTheRight && direction === 'explode' || !toTheRight && direction === 'implode') { @@ -154,27 +154,23 @@ export class PieChart extends BaseChart { * @param options */ createChart(options) { - var data = normalizeData(this.data); - var seriesGroups = [], - labelsGroup, - chartRect, - radius, - labelRadius, - totalDataSum, - startAngle = options.startAngle; + const data = normalizeData(this.data); + const seriesGroups = []; + let labelsGroup; + let labelRadius; + let startAngle = options.startAngle; // Create SVG.js draw this.svg = createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie); // Calculate charting rect - chartRect = createChartRect(this.svg, options, defaultOptions.padding); + const chartRect = createChartRect(this.svg, options, defaultOptions.padding); // Get biggest circle radius possible within chartRect - radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + let radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || data.normalized.series.reduce(function (previousValue, currentValue) { - return previousValue + currentValue; - }, 0); + const totalDataSum = options.total || + data.normalized.series.reduce(sum, 0); - var donutWidth = quantity(options.donutWidth); + const donutWidth = quantity(options.donutWidth); if (donutWidth.unit === '%') { donutWidth.value *= radius / 100; } @@ -200,20 +196,19 @@ export class PieChart extends BaseChart { labelRadius += options.labelOffset; // Calculate end angle based on total sum and current data value and offset with padding - var center = { + const center = { x: chartRect.x1 + chartRect.width() / 2, y: chartRect.y2 + chartRect.height() / 2 }; // Check if there is only one non-zero value in the series array. - var hasSingleValInSeries = data.raw.series.filter(function (val) { - return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; - }).length === 1; + const hasSingleValInSeries = data.raw.series + .filter((val) => val.hasOwnProperty('value') ? val.value !== 0 : val !== 0) + .length === 1; // Creating the series groups - data.raw.series.forEach(function (series, index) { - seriesGroups[index] = this.svg.elem('g', null, null); - }.bind(this)); + data.raw.series + .forEach((series, index) => seriesGroups[index] = this.svg.elem('g', null, null)); //if we need to show labels we create the label group now if (options.showLabel) { labelsGroup = this.svg.elem('g', null, null); @@ -221,7 +216,7 @@ export class PieChart extends BaseChart { // Draw the series // initialize series groups - data.raw.series.forEach(function (series, index) { + data.raw.series.forEach((series, index) => { // If current value is zero and we are ignoring empty values then skip to next value if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; @@ -233,14 +228,14 @@ export class PieChart extends BaseChart { // Use series class from series data or if not set generate one seriesGroups[index].addClass([ options.classNames.series, - (series.className || options.classNames.series + '-' + alphaNumerate(index)) + series.className || `${options.classNames.series}-${alphaNumerate(index)}` ].join(' ')); // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. - var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0); + let endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0); // Use slight offset so there are no transparent hairline issues - var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); + const overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees @@ -248,11 +243,11 @@ export class PieChart extends BaseChart { endAngle = overlappigStartAngle + 359.99; } - var start = polarToCartesian(center.x, center.y, radius, overlappigStartAngle), - end = polarToCartesian(center.x, center.y, radius, endAngle); + const start = polarToCartesian(center.x, center.y, radius, overlappigStartAngle); + const end = polarToCartesian(center.x, center.y, radius, endAngle); // 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 SvgPath(!options.donut) + const path = new SvgPath(!options.donut) .move(end.x, end.y) .arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y); @@ -263,7 +258,7 @@ export class PieChart extends BaseChart { // Create the SVG path // If this is a donut chart we add the donut class, otherwise just a regular slice - var pathElement = seriesGroups[index].elem('path', { + const pathElement = seriesGroups[index].elem('path', { d: path.stringify() }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie); @@ -299,7 +294,8 @@ export class PieChart extends BaseChart { // If we need to show labels we need to add the label for this slice now if (options.showLabel) { - var labelPosition; + let labelPosition; + if (data.raw.series.length === 1) { // If we have only 1 series, we can position the label in the center of the pie labelPosition = { @@ -316,14 +312,14 @@ export class PieChart extends BaseChart { ); } - var rawValue; + let rawValue; if (data.normalized.labels && !isFalseyButZero(data.normalized.labels[index])) { rawValue = data.normalized.labels[index]; } else { rawValue = data.normalized.series[index]; } - var interpolatedValue = options.labelInterpolationFnc(rawValue, index); + const interpolatedValue = options.labelInterpolationFnc(rawValue, index); if (interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { @@ -335,7 +331,7 @@ export class PieChart extends BaseChart { // Fire off draw event this.eventEmitter.emit('draw', { type: 'label', - index: index, + index, group: labelsGroup, element: labelElement, text: '' + interpolatedValue, @@ -348,12 +344,12 @@ export class PieChart extends BaseChart { // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; - }.bind(this)); + }); this.eventEmitter.emit('created', { - chartRect: chartRect, + chartRect, svg: this.svg, - options: options + options }); } } diff --git a/src/charts/pie.spec.js b/src/charts/pie.spec.js new file mode 100644 index 00000000..c0a7e2ba --- /dev/null +++ b/src/charts/pie.spec.js @@ -0,0 +1,442 @@ +import {initializeFixtures, destroyFixtures, addFixture} from '../testing/fixtures'; +import {namespaces} from '../core/globals'; +import {deserialize} from '../core/data'; +import {PieChart} from './pie'; + +describe('PieChart', () => { + beforeEach(() => initializeFixtures()); + afterEach(() => destroyFixtures()); + + describe('Meta data tests', () => { + + it('should render meta data correctly on slice with mixed value array', (done) => { + const fixture = addFixture('
    '); + const meta = { + test: 'Serialized Test' + }; + + const data = { + labels: ['A', 'B', 'C'], + series: [5, { + value: 8, + meta: meta + }, 1] + }; + + const chartContainer = fixture.wrapper.querySelector('.ct-chart'); + const chart = new PieChart(chartContainer, data); + + chart.on('created', () => { + const metaAttribute = chartContainer + .querySelectorAll('.ct-slice-pie')[1] + .getAttributeNS(namespaces.ct, 'meta'); + expect(deserialize(metaAttribute)).toEqual(meta); + chart.off('created'); + done(); + }); + }); + }); + + describe('Simple Pie Chart', () => { + const num = '\\d+(\\.\\d*)?'; + const sum = (a, b) => a + b; + let data; + let options; + let fixture; + + beforeEach(() => { + data = { + series: [5, 3, 4] + }; + options = { + width: 100, + height: 100, + chartPadding: 10, + labelInterpolationFnc: (value) => `${Math.round(value / data.series.reduce(sum) * 100)}%` + }; + }); + + function createChart(callback) { + fixture = addFixture('
    '); + const chart = new PieChart(fixture.wrapper.querySelector('.ct-chart'), data, options) + .on('created', () => { + callback(); + chart.off('created'); + }); + } + + it('should render three slices', (done) => { + createChart(() => { + expect(fixture.wrapper.querySelectorAll('.ct-slice-pie').length).toBe(3); + done(); + }); + }); + + it('should set value attribute', (done) => { + createChart(() => { + const slices = fixture.wrapper.querySelectorAll('.ct-slice-pie'); + expect(slices[0].getAttributeNS(namespaces.ct, 'value')).toBe('5'); + expect(slices[1].getAttributeNS(namespaces.ct, 'value')).toBe('3'); + expect(slices[2].getAttributeNS(namespaces.ct, 'value')).toBe('4'); + done(); + }); + }); + + it('should create slice path', (done) => { + createChart(() => { + Array.from(fixture.wrapper.querySelectorAll('.ct-slice-pie')).forEach((element) => { + const pattern = `M${num},${num}A40,40,0,0,0,${num},${num}L50,50Z$`; + const path = element.getAttribute('d'); + expect(path).toMatch(pattern); + }); + done(); + }); + }); + + it('should add labels', (done) => { + createChart(() => { + const labels = fixture.wrapper.querySelectorAll('.ct-label'); + expect(labels[0].textContent).toBe('42%'); + expect(labels[1].textContent).toBe('25%'); + expect(labels[2].textContent).toBe('33%'); + done(); + }); + }); + + it('should overlap slices', (done) => { + data = { + series: [1, 1] + }; + createChart(() => { + const [slice1, slice2] = Array.from(fixture.wrapper.querySelectorAll('.ct-slice-pie')); + + expect(slice1.getAttribute('d')).toMatch(/^M50,90A40,40,0,0,0,50,10L50,50Z/); + expect(slice2.getAttribute('d')).toMatch(/^M50,10A40,40,0,0,0,50.\d+,90L50,50Z/); + done(); + }); + }); + + it('should set large arc sweep flag', (done) => { + data = { + series: [1, 2] + }; + createChart(() => { + const slice = fixture.wrapper.querySelectorAll('.ct-slice-pie')[1]; + expect(slice.getAttribute('d')).toMatch(/^M50,10A40,40,0,1,0/); + done(); + }, data); + }); + + it('should draw complete circle with gap', (done) => { + data = { + series: [1] + }; + createChart(() => { + const slice = fixture.wrapper.querySelectorAll('.ct-slice-pie')[0]; + expect(slice.getAttribute('d')).toMatch(/^M49.9\d+,10A40,40,0,1,0,50,10L50,50Z/); + done(); + }); + }); + + it('should draw complete circle with startAngle', (done) => { + data.series = [100]; + options.startAngle = 90; + createChart(() => { + const slice = fixture.wrapper.querySelectorAll('.ct-slice-pie')[0]; + expect(slice.getAttribute('d')).toMatch(/^M90,49.9\d+A40,40,0,1,0,90,50L50,50Z/); + done(); + }); + }); + + it('should draw complete circle if values are 0', (done) => { + data = { + series: [0, 1, 0] + }; + createChart(() => { + const slice = fixture.wrapper.querySelectorAll('.ct-slice-pie')[1]; + expect(slice.getAttribute('d')).toMatch(/^M49.9\d+,10A40,40,0,1,0,50,10L50,50Z/); + done(); + }); + }); + + }); + + describe('Pie with small slices', () => { + let data; + let options; + let fixture; + + beforeEach(() => { + data = { + series: [0.001, 2] + }; + options = { + width: 100, + height: 100, + chartPadding: 0 + }; + }); + + function createChart(callback) { + fixture = addFixture('
    '); + const chart = new PieChart(fixture.wrapper.querySelector('.ct-chart'), data, options) + .on('created', () => { + callback(); + chart.off('created'); + }); + } + + it('should render correctly with very small slices', (done) => { + createChart(() => { + const [slice1, slice2] = Array.from(fixture.wrapper.querySelectorAll('.ct-slice-pie')); + + expect(slice1.getAttribute('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/); + expect(slice2.getAttribute('d')).toMatch(/^M49.9\d*,0A50,50,0,1,0,50,0/); + done(); + }); + }); + + it('should render correctly with very small slices on startAngle', (done) => { + options.startAngle = 90; + createChart(() => { + const [slice1, slice2] = Array.from(fixture.wrapper.querySelectorAll('.ct-slice-pie')); + + expect(slice1.getAttribute('d')).toMatch(/^M100,50.1\d*A50,50,0,0,0,100,50/); + expect(slice2.getAttribute('d')).toMatch(/^M100,49.97\d*A50,50,0,1,0,100,49.98\d*/); + done(); + }); + }); + + it('should render correctly with very small slices', (done) => { + options.donut = true; + createChart(() => { + const [slice1, slice2] = Array.from(fixture.wrapper.querySelectorAll('.ct-slice-donut')); + + expect(slice1.getAttribute('d')).toMatch(/^M50.\d+,30A20,20,0,0,0,50,30/); + expect(slice2.getAttribute('d')).toMatch(/^M49.9\d*,30A20,20,0,1,0,50,30/); + done(); + }); + }); + }); + + describe('Pie with empty values', () => { + let data; + let options; + let fixture; + + beforeEach(() => { + data = { + series: [1, 2, 0, 4] + }; + options = { + width: 100, + height: 100, + ignoreEmptyValues: true + }; + }); + + function createChart(callback) { + fixture = addFixture('
    '); + const chart = new PieChart(fixture.wrapper.querySelector('.ct-chart'), data, options) + .on('created', () => { + callback(); + chart.off('created'); + }); + } + + it('should not render empty slices', (done) => { + createChart(() => { + const slices = fixture.wrapper.querySelectorAll('.ct-slice-pie'); + + expect(slices.length).toBe(3); + expect(slices[0].getAttributeNS(namespaces.ct, 'value')).toBe('1'); + expect(slices[1].getAttributeNS(namespaces.ct, 'value')).toBe('2'); + expect(slices[2].getAttributeNS(namespaces.ct, 'value')).toBe('4'); + done(); + }); + }); + + it('should render without NaN values and points', (done) => { + data = { + series: [0, 0, 0] + }; + options = { + width: 400, + height: 400 + }; + + createChart(() => { + const slices = fixture.wrapper.querySelectorAll('.ct-slice-pie'); + + expect(slices.length).toBe(3); + + expect(slices[0].getAttributeNS(namespaces.ct, 'value')).toBe('0'); + expect(slices[1].getAttributeNS(namespaces.ct, 'value')).toBe('0'); + expect(slices[2].getAttributeNS(namespaces.ct, 'value')).toBe('0'); + + expect(slices[0].getAttribute('d')).toBe('M200,5A195,195,0,0,0,200,5L200,200Z'); + expect(slices[1].getAttribute('d')).toBe('M200,5A195,195,0,0,0,200,5L200,200Z'); + expect(slices[2].getAttribute('d')).toBe('M200,5A195,195,0,0,0,200,5L200,200Z'); + done(); + }); + }); + + it('should render empty slices', (done) => { + data = { + series: [1, 2, 0, 4] + }; + options = { + width: 100, + height: 100, + ignoreEmptyValues: false + }; + + createChart(() => { + const slices = fixture.wrapper.querySelectorAll('.ct-slice-pie'); + + expect(slices.length).toBe(4); + + expect(slices[0].getAttributeNS(namespaces.ct, 'value')).toBe('1'); + expect(slices[1].getAttributeNS(namespaces.ct, 'value')).toBe('2'); + expect(slices[2].getAttributeNS(namespaces.ct, 'value')).toBe('0'); + expect(slices[3].getAttributeNS(namespaces.ct, 'value')).toBe('4'); + done(); + }); + }); + }); + + describe('Gauge Chart', () => { + let fixture; + let data; + let options; + + beforeEach(() => { + data = { + series: [20, 10, 30, 40] + }; + options = { + chartPadding: 50, + height: 500, + width: 500, + donut: true, + donutWidth: 60, + startAngle: 270, + total: 200, + showLabel: false + } + }); + + function createChart(callback) { + fixture = addFixture('
    '); + const chart = new PieChart(fixture.wrapper.querySelector('.ct-chart'), data, options) + .on('created', () => { + callback(); + chart.off('created'); + }); + } + + it('should render four strokes', (done) => { + createChart(() => { + expect(fixture.wrapper.querySelectorAll('.ct-slice-donut').length).toBe(4); + done(); + }); + }); + + it('should set value attribute', (done) => { + createChart(() => { + const slices = fixture.wrapper.querySelectorAll('.ct-slice-donut'); + expect(slices[0].getAttributeNS(namespaces.ct, 'value')).toBe('20'); + expect(slices[1].getAttributeNS(namespaces.ct, 'value')).toBe('10'); + expect(slices[2].getAttributeNS(namespaces.ct, 'value')).toBe('30'); + expect(slices[3].getAttributeNS(namespaces.ct, 'value')).toBe('40'); + done(); + }); + }); + + it('should create slice path', (done) => { + const num = '\\d+(\\.\\d*)?'; + const pattern = `^M${num},${num}A170,170,0,0,0,${num},${num}$`; + + createChart(() => { + Array.from(fixture.wrapper.querySelectorAll('.ct-slice-donut')) + .forEach((element) => expect(element.getAttribute('d')).toMatch(pattern)); + done(); + }); + }); + + it('should set stroke-width', (done) => { + const strokeWidth = 'stroke-width:\\s*60px'; + + createChart(() => { + Array.from(fixture.wrapper.querySelectorAll('.ct-slice-donut')) + .forEach((element) => expect(element.getAttribute('style')).toMatch(strokeWidth)); + done(); + }); + }); + + it('should not add labels', (done) => { + createChart(() => { + const labels = fixture.wrapper.querySelectorAll('.ct-label'); + expect(labels.length).toBe(0); + done(); + }); + }); + }); + + describe('Pie Chart with relative donutWidth', () => { + let fixture; + let data; + let options; + + beforeEach(() => { + data = { + series: [20, 10, 30, 40] + }; + options = { + chartPadding: 50, + height: 500, + width: 500, + donut: true, + donutWidth: '25%', + showLabel: false + }; + }); + + function createChart(callback) { + fixture = addFixture('
    '); + const chart = new PieChart(fixture.wrapper.querySelector('.ct-chart'), data, options) + .on('created', () => { + callback(); + chart.off('created'); + }); + } + + it('should render four strokes', (done) => { + createChart(() => { + expect(fixture.wrapper.querySelectorAll('.ct-slice-donut').length).toBe(4); + done(); + }); + }); + + it('should create slice path', (done) => { + const num = '\\d+(\\.\\d*)?'; + const pattern = `^M${num},${num}A175,175,0,0,0,${num},${num}$`; + + createChart(() => { + Array.from(fixture.wrapper.querySelectorAll('.ct-slice-donut')) + .forEach((element) => expect(element.getAttribute('d')).toMatch(pattern)); + done(); + }); + }); + + it('should set stroke-width', (done) => { + const strokeWidth = 'stroke-width:\\s?50px'; + + createChart(() => { + Array.from(fixture.wrapper.querySelectorAll('.ct-slice-donut')) + .forEach((element) => expect(element.getAttribute('style')).toMatch(strokeWidth)); + done(); + }); + }); + }); +}); diff --git a/src/core/creation.js b/src/core/creation.js index dfe1c86b..623f2fe6 100644 --- a/src/core/creation.js +++ b/src/core/creation.js @@ -13,26 +13,20 @@ import {extend} from './extend'; * @param {String} className Specify a class to be added to the SVG element * @return {Object} The created/reinitialized SVG element */ -export function createSvg(container, width, height, className) { - var svg; - - width = width || '100%'; - height = height || '100%'; - +export function createSvg(container, width = '100%', height = '100%', className) { // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ - Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { - return svg.getAttributeNS(namespaces.xmlns, 'ct'); - }).forEach(function removePreviousElement(svg) { - container.removeChild(svg); - }); + Array.from(container.querySelectorAll('svg')) + .filter((svg) => svg.getAttributeNS(namespaces.xmlns, 'ct')) + .forEach((svg) => container.removeChild(svg)); // Create svg object with width and height or use 100% as default - svg = new Svg('svg').attr({ - width: width, - height: height + const svg = new Svg('svg').attr({ + width, + height }).addClass(className).attr({ - style: 'width: ' + width + '; height: ' + height + ';' + // TODO: Check better solution (browser support) and remove inline styles due to CSP + style: `width: ${width}; height: ${height};` }); // Add the DOM node to our container @@ -49,9 +43,7 @@ export function createSvg(container, width, height, className) { * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed * @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. */ -export function normalizePadding(padding, fallback) { - fallback = fallback || 0; - +export function normalizePadding(padding, fallback = 0) { return typeof padding === 'number' ? { top: padding, right: padding, @@ -75,29 +67,29 @@ export function normalizePadding(padding, fallback) { * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ export function createChartRect(svg, options, fallbackPadding) { - var hasAxis = !!(options.axisX || options.axisY); - var yAxisOffset = hasAxis ? options.axisY.offset : 0; - var xAxisOffset = hasAxis ? options.axisX.offset : 0; + const hasAxis = !!(options.axisX || options.axisY); + const yAxisOffset = hasAxis ? options.axisY.offset : 0; + const xAxisOffset = hasAxis ? options.axisX.offset : 0; // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 - var width = svg.width() || quantity(options.width).value || 0; - var height = svg.height() || quantity(options.height).value || 0; - var normalizedPadding = normalizePadding(options.chartPadding, fallbackPadding); + let width = svg.width() || quantity(options.width).value || 0; + let height = svg.height() || quantity(options.height).value || 0; + const normalizedPadding = normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right); height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom); - var chartRect = { + const chartRect = { padding: normalizedPadding, - width: function () { + width: function() { return this.x2 - this.x1; }, - height: function () { + height: function() { return this.y1 - this.y2; } }; - if(hasAxis) { + if (hasAxis) { if (options.axisX.position === 'start') { chartRect.y2 = normalizedPadding.top + xAxisOffset; chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); @@ -137,21 +129,21 @@ export function createChartRect(svg, options, fallbackPadding) { * @param eventEmitter */ export function createGrid(position, index, axis, offset, length, group, classes, eventEmitter) { - var positionalData = {}; - positionalData[axis.units.pos + '1'] = position; - positionalData[axis.units.pos + '2'] = position; - positionalData[axis.counterUnits.pos + '1'] = offset; - positionalData[axis.counterUnits.pos + '2'] = offset + length; + const positionalData = {}; + positionalData[`${axis.units.pos}1`] = position; + positionalData[`${axis.units.pos}2`] = position; + positionalData[`${axis.counterUnits.pos}1`] = offset; + positionalData[`${axis.counterUnits.pos}2`] = offset + length; - var gridElement = group.elem('line', positionalData, classes.join(' ')); + const gridElement = group.elem('line', positionalData, classes.join(' ')); // Event for grid draw eventEmitter.emit('draw', extend({ type: 'grid', - axis: axis, - index: index, - group: group, + axis, + index, + group, element: gridElement }, positionalData) ); @@ -167,7 +159,7 @@ export function createGrid(position, index, axis, offset, length, group, classes * @param eventEmitter */ export function createGridBackground(gridGroup, chartRect, className, eventEmitter) { - var gridBackground = gridGroup.elem('rect', { + const gridBackground = gridGroup.elem('rect', { x: chartRect.x1, y: chartRect.y2, width: chartRect.width(), @@ -199,21 +191,25 @@ export function createGridBackground(gridGroup, chartRect, className, eventEmitt * @param eventEmitter */ export function createLabel(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { - var labelElement; - var positionalData = {}; + let labelElement; + const positionalData = {}; positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; positionalData[axis.units.len] = length; positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10); - if(useForeignObject) { + 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] + ''; + const length = Math.round(positionalData[axis.units.len]); + const counterLength = Math.round(positionalData[axis.counterUnits.len]); + const content = ` + + ${labels[index]} + + `.trim(); labelElement = group.foreignObject(content, extend({ style: 'overflow: visible;' @@ -224,9 +220,9 @@ export function createLabel(position, length, index, labels, axis, axisOffset, l eventEmitter.emit('draw', extend({ type: 'label', - axis: axis, - index: index, - group: group, + axis, + index, + group, element: labelElement, text: labels[index] }, positionalData)); diff --git a/src/core/creation.spec.js b/src/core/creation.spec.js index 2893b411..59baf789 100644 --- a/src/core/creation.spec.js +++ b/src/core/creation.spec.js @@ -51,10 +51,10 @@ describe('Creation', () => { group = new Svg('g'); axis = { units: { - pos : 'x' + pos: 'x' }, counterUnits: { - pos : 'y' + pos: 'y' } }; classes = []; diff --git a/src/core/data.js b/src/core/data.js index 5c426b0d..19ebcb98 100644 --- a/src/core/data.js +++ b/src/core/data.js @@ -2,7 +2,7 @@ import {escapingMap} from './globals'; import {replaceAll, safeHasProperty, getNumberOrUndefined} from './lang'; import {times} from './functional'; import {extend} from './extend'; -import {orderOfMagnitude, projectLength, roundWithPrecision, rho} from './math'; +import {orderOfMagnitude, projectLength, roundWithPrecision, rho, EPSILON} from './math'; /** * 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. @@ -16,14 +16,13 @@ export function serialize(data) { if(data === null || data === undefined) { return data; } else if(typeof data === 'number') { - data = ''+data; + data = '' + data; } else if(typeof data === 'object') { data = JSON.stringify({data: data}); } - return Object.keys(escapingMap).reduce(function(result, key) { - return replaceAll(result, key, escapingMap[key]); - }, data); + return Object.keys(escapingMap) + .reduce((result, key) => replaceAll(result, key, escapingMap[key]), data); } /** @@ -38,14 +37,14 @@ export function deserialize(data) { return data; } - data = Object.keys(escapingMap).reduce(function(result, key) { - return replaceAll(result, escapingMap[key], key); - }, data); + data = Object.keys(escapingMap) + .reduce((result, key) => replaceAll(result, escapingMap[key], key), data); try { data = JSON.parse(data); data = data.data !== undefined ? data.data : data; - } catch(e) {} + } catch(e) { + } return data; } @@ -57,8 +56,8 @@ export function deserialize(data) { * @return {Object} The normalized data object */ export function normalizeData(data, reverse, multi) { - var labelCount; - var output = { + let labelCount; + const output = { raw: data, normalized: {} }; @@ -70,13 +69,9 @@ export function normalizeData(data, reverse, multi) { // If all elements of the normalized data array are arrays we're dealing with // multi series data and we need to find the largest series if they are un-even - if (output.normalized.series.every(function(value) { - return value instanceof Array; - })) { + if(output.normalized.series.every((value) => value instanceof Array)) { // Getting the series with the the most elements - labelCount = Math.max.apply(null, output.normalized.series.map(function(series) { - return series.length; - })); + labelCount = Math.max(...output.normalized.series.map((series) => series.length)); } else { // We're dealing with Pie data so we just take the normalized array length labelCount = output.normalized.series.length; @@ -84,12 +79,9 @@ export function normalizeData(data, reverse, multi) { output.normalized.labels = (data.labels || []).slice(); // Padding the labels to labelCount with empty strings - Array.prototype.push.apply( - output.normalized.labels, - times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() { - return ''; - }) - ); + output.normalized.labels + .push(...times(Math.max(0, labelCount - output.normalized.labels.length)) + .map(() => '')); if(reverse) { reverseData(output.normalized); @@ -106,7 +98,7 @@ export function normalizeData(data, reverse, multi) { * @returns {*} */ export function getMetaData(series, index) { - var value = series.data ? series.data[index] : series[index]; + const value = series.data ? series.data[index] : series[index]; return value ? value.meta : undefined; } @@ -131,11 +123,11 @@ export function isDataHoleValue(value) { export function reverseData(data) { data.labels.reverse(); data.series.reverse(); - for (var i = 0; i < data.series.length; i++) { - if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { - data.series[i].data.reverse(); - } else if(data.series[i] instanceof Array) { - data.series[i].reverse(); + for(let series of data.series) { + if(typeof(series) === 'object' && series.data !== undefined) { + series.data.reverse(); + } else if(series instanceof Array) { + series.reverse(); } } } @@ -202,7 +194,8 @@ export function getDataArray(data, reverse, multi) { * @param value */ export function isMultiValue(value) { - return typeof value === 'object' && ('x' in value || 'y' in value); + return typeof value === 'object' && + (value.hasOwnProperty('x') || value.hasOwnProperty('y')); } /** @@ -211,12 +204,11 @@ export function isMultiValue(value) { * @memberof Chartist.Core * @param value * @param dimension - * @param defaultValue * @returns {*} */ -export function getMultiValue(value, dimension) { +export function getMultiValue(value, dimension = 'y') { if(isMultiValue(value)) { - return getNumberOrUndefined(value[dimension || 'y']); + return getNumberOrUndefined(value[dimension]); } else { return getNumberOrUndefined(value); } @@ -233,7 +225,7 @@ export function getMultiValue(value, dimension) { */ export function getSeriesOption(series, options, key) { if(series.name && options.series && options.series[series.name]) { - var seriesOptions = options.series[series.name]; + const seriesOptions = options.series[series.name]; return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key]; } else { return options[key]; @@ -265,17 +257,17 @@ export function getSeriesOption(series, options, key) { * @return {Array} List of segments, each containing a pathCoordinates and valueData property. */ export function splitIntoSegments(pathCoordinates, valueData, options) { - var defaultOptions = { + const defaultOptions = { increasingX: false, fillHoles: false }; options = extend({}, defaultOptions, options); - var segments = []; - var hole = true; + const segments = []; + let hole = true; - for(var i = 0; i < pathCoordinates.length; i += 2) { + for(let i = 0; i < pathCoordinates.length; i += 2) { // If this value is a "hole" we set the hole flag if(getMultiValue(valueData[i / 2].value) === undefined) { // if(valueData[i / 2].value === undefined) { @@ -283,7 +275,7 @@ export function splitIntoSegments(pathCoordinates, valueData, options) { hole = true; } } else { - if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) { + if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i - 2]) { // X is not increasing, so we need to make sure we start a new segment hole = true; } @@ -321,29 +313,29 @@ export function getHighLow(data, options, dimension) { // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred options = extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {}); - var highLow = { + const highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low }; - var findHigh = options.high === undefined; - var findLow = options.low === undefined; + const findHigh = options.high === undefined; + const findLow = options.low === undefined; // Function to recursively walk through arrays and find highest and lowest number function recursiveHighLow(data) { if(data === undefined) { return undefined; } else if(data instanceof Array) { - for (var i = 0; i < data.length; i++) { + for(let i = 0; i < data.length; i++) { recursiveHighLow(data[i]); } } else { - var value = dimension ? +data[dimension] : +data; + const value = dimension ? +data[dimension] : +data; - if (findHigh && value > highLow.high) { + if(findHigh && value > highLow.high) { highLow.high = value; } - if (findLow && value < highLow.low) { + if(findLow && value < highLow.low) { highLow.low = value; } } @@ -357,21 +349,21 @@ export function getHighLow(data, options, dimension) { // Overrides of high / low based on reference value, it will make sure that the invisible reference value is // used to generate the chart. This is useful when the chart always needs to contain the position of the // invisible reference value in the view i.e. for bipolar scales. - if (options.referenceValue || options.referenceValue === 0) { + if(options.referenceValue || options.referenceValue === 0) { highLow.high = Math.max(options.referenceValue, highLow.high); highLow.low = Math.min(options.referenceValue, highLow.low); } // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity - if (highLow.high <= highLow.low) { + if(highLow.high <= highLow.low) { // If both values are 0 we set high to 1 - if (highLow.low === 0) { + if(highLow.low === 0) { highLow.high = 1; - } else if (highLow.low < 0) { + } else if(highLow.low < 0) { // If we have the same negative value for the bounds we set bounds.high to 0 highLow.high = 0; - } else if (highLow.high > 0) { + } else if(highLow.high > 0) { // If we have the same positive value for the bounds we set bounds.low to 0 highLow.low = 0; } else { @@ -395,14 +387,10 @@ export function getHighLow(data, options, dimension) { * @return {Object} All the values to set the bounds of the chart */ export function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { - var i, - optimizationCounter = 0, - newMin, - newMax, - bounds = { - high: highLow.high, - low: highLow.low - }; + const bounds = { + high: highLow.high, + low: highLow.low + }; bounds.valueRange = bounds.high - bounds.low; bounds.oom = orderOfMagnitude(bounds.valueRange); @@ -414,9 +402,9 @@ export function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace // If we are already below the scaleMinSpace value we will scale up - var length = projectLength(axisLength, bounds.step, bounds); - var scaleUp = length < scaleMinSpace; - var smallestFactor = onlyInteger ? rho(bounds.range) : 0; + const length = projectLength(axisLength, bounds.step, bounds); + const scaleUp = length < scaleMinSpace; + const smallestFactor = onlyInteger ? rho(bounds.range) : 0; // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1 if(onlyInteger && projectLength(axisLength, 1, bounds) >= scaleMinSpace) { @@ -428,10 +416,11 @@ export function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { bounds.step = smallestFactor; } else { // Trying to divide or multiply by 2 and find the best step value - while (true) { - if (scaleUp && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { + let optimizationCounter = 0; + while(true) { + if(scaleUp && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { bounds.step *= 2; - } else if (!scaleUp && projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { + } else if(!scaleUp && projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { bounds.step /= 2; if(onlyInteger && bounds.step % 1 !== 0) { bounds.step *= 2; @@ -447,36 +436,36 @@ export function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { } } - var EPSILON = 2.221E-16; bounds.step = Math.max(bounds.step, EPSILON); function safeIncrement(value, increment) { // If increment is too small use *= (1+EPSILON) as a simple nextafter - if (value === (value += increment)) { + if(value === (value += increment)) { value *= (1 + (increment > 0 ? EPSILON : -EPSILON)); } return value; } // Narrow min and max based on new step - newMin = bounds.min; - newMax = bounds.max; - while (newMin + bounds.step <= bounds.low) { + let newMin = bounds.min; + let newMax = bounds.max; + while(newMin + bounds.step <= bounds.low) { newMin = safeIncrement(newMin, bounds.step); } - while (newMax - bounds.step >= bounds.high) { + while(newMax - bounds.step >= bounds.high) { newMax = safeIncrement(newMax, -bounds.step); } bounds.min = newMin; bounds.max = newMax; bounds.range = bounds.max - bounds.min; - var values = []; - for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { + const values = []; + for(let i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { var value = roundWithPrecision(i); - if (value !== values[values.length - 1]) { + if(value !== values[values.length - 1]) { values.push(value); } } bounds.values = values; + return bounds; } diff --git a/src/core/data.spec.js b/src/core/data.spec.js index 16b96592..7990bce6 100644 --- a/src/core/data.spec.js +++ b/src/core/data.spec.js @@ -276,7 +276,7 @@ describe('Data', () => { }); it('should return single step if range is less than epsilon', () => { - const bounds = getBounds(100, { high: 1.0000000000000002, low: 1 }, 20, false); + const bounds = getBounds(100, {high: 1.0000000000000002, low: 1}, 20, false); expect(bounds.min).toBe(1); expect(bounds.max).toBe(1.0000000000000002); expect(bounds.low).toBe(1); @@ -296,7 +296,7 @@ describe('Data', () => { describe('splitIntoSegments', () => { function makeValues(arr) { - return arr.map(function (x) { + return arr.map(function(x) { return {value: x}; }); } diff --git a/src/core/extend.js b/src/core/extend.js index 610a3a31..f6bd4071 100644 --- a/src/core/extend.js +++ b/src/core/extend.js @@ -6,15 +6,14 @@ * @param {Object...} sources This object (objects) will be merged into target and then target is returned * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source */ -export function extend(target) { - var i, source, sourceProp; +export function extend(target = {}, ...sources) { target = target || {}; - for (i = 1; i < arguments.length; i++) { - source = arguments[i]; - for (var prop in source) { - sourceProp = source[prop]; - if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { + for(let i = 0; i < sources.length; i++) { + const source = sources[i]; + for(let prop in source) { + const sourceProp = source[prop]; + if(typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { target[prop] = extend(target[prop], sourceProp); } else { target[prop] = sourceProp; diff --git a/src/core/functional.js b/src/core/functional.js index 465b5e05..fbb92d88 100644 --- a/src/core/functional.js +++ b/src/core/functional.js @@ -5,9 +5,7 @@ * @param {*} n This exact value will be returned by the noop function * @return {*} The same value that was provided to the n parameter */ -export function noop(n) { - return n; -} +export const noop = (n) => n; /** * Functional style helper to produce array with given length initialized with undefined values @@ -16,9 +14,7 @@ export function noop(n) { * @param length * @return {Array} */ -export function times(length) { - return Array.apply(null, new Array(length)); -} +export const times = (length) => Array.from({length}); /** * Sum helper to be used in reduce functions @@ -28,57 +24,27 @@ export function times(length) { * @param current * @return {*} */ -export function sum(previous, current) { - return previous + (current ? current : 0); -} +export const sum = (previous, current) => previous + (current ? current : 0); /** - * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor. + * 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). * - * @memberof Chartist.Core - * @param {Number} factor - * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array - */ -export function mapMultiply(factor) { - return function(num) { - return num * factor; - }; -} - -/** - * Add helper to be used in `Array.map` for adding a addend to each value of an array. + * For example: + * @example + * ```javascript + * const data = [[1, 2], [3], []]; + * serialMap(data, cb); * - * @memberof Chartist.Core - * @param {Number} addend - * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array - */ -export function mapAdd(addend) { - return function(num) { - return num + addend; - }; -} - -/** - * 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). + * // where cb will be called 2 times + * // 1. call arguments: (1, 3, undefined) + * // 2. call arguments: (2, undefined, undefined) + * ``` * * @memberof Chartist.Core * @param arr * @param cb * @return {Array} */ -export function serialMap(arr, cb) { - var result = [], - length = Math.max.apply(null, arr.map(function(e) { - return e.length; - })); - - times(length).forEach(function(e, index) { - var args = arr.map(function(e) { - return e[index]; - }); - - result[index] = cb.apply(null, args); - }); - - return result; -} +export const serialMap = (arr, cb) => + times(Math.max(...arr.map((e) => e.length))) + .map((e, index) => cb(...arr.map((e) => e[index]))); diff --git a/src/core/lang.js b/src/core/lang.js index ccf189b7..8d35b22f 100644 --- a/src/core/lang.js +++ b/src/core/lang.js @@ -92,13 +92,16 @@ export function ensureUnit(value, unit) { */ export function quantity(input) { if (typeof input === 'string') { - var match = (/^(\d+)\s*(.*)$/g).exec(input); + const match = (/^(\d+)\s*(.*)$/g).exec(input); return { value : +match[1], unit: match[2] || undefined }; } - return { value: input }; + + return { + value: input + }; } /** diff --git a/src/core/math.js b/src/core/math.js index de5a11e9..0dadbbe0 100644 --- a/src/core/math.js +++ b/src/core/math.js @@ -1,5 +1,7 @@ import {precision as globalPrecision} from './globals'; +export const EPSILON = 2.221E-16; + /** * Calculate the order of magnitude for the chart scale * @@ -33,7 +35,7 @@ export function projectLength(axisLength, length, bounds) { * @returns {number} Rounded value */ export function roundWithPrecision(value, digits) { - var precision = Math.pow(10, digits || globalPrecision); + const precision = Math.pow(10, digits || globalPrecision); return Math.round(value * precision) / precision; } @@ -61,7 +63,9 @@ export function rho(num) { return x * x + 1; } - var x1 = 2, x2 = 2, divisor; + let x1 = 2; + let x2 = 2; + let divisor; if (num % 2 === 0) { return 2; } @@ -86,7 +90,7 @@ export function rho(num) { * @return {{x:Number, y:Number}} Coordinates of point on circumference */ export function polarToCartesian(centerX, centerY, radius, angleInDegrees) { - var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; + const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; return { x: centerX + (radius * Math.cos(angleInRadians)), diff --git a/src/core/options-provider.js b/src/core/options-provider.js index 18c4a1aa..b6dff106 100644 --- a/src/core/options-provider.js +++ b/src/core/options-provider.js @@ -10,54 +10,50 @@ import {extend} from './extend'; * @return {Object} The consolidated options object from the defaults, base and matching responsive options */ export function optionsProvider(options, responsiveOptions, eventEmitter) { - var baseOptions = extend({}, options), - currentOptions, - mediaQueryListeners = [], - i; + const baseOptions = extend({}, options); + let currentOptions; + const mediaQueryListeners = []; function updateCurrentOptions(mediaEvent) { - var previousOptions = currentOptions; + const previousOptions = currentOptions; currentOptions = extend({}, baseOptions); if (responsiveOptions) { - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); + responsiveOptions.forEach((responsiveOption) => { + const mql = window.matchMedia(responsiveOption[0]); if (mql.matches) { - currentOptions = extend(currentOptions, responsiveOptions[i][1]); + currentOptions = extend(currentOptions, responsiveOption[1]); } - } + }); } if(eventEmitter && mediaEvent) { eventEmitter.emit('optionsChanged', { - previousOptions: previousOptions, - currentOptions: currentOptions + previousOptions, + currentOptions }); } } function removeMediaQueryListeners() { - mediaQueryListeners.forEach(function(mql) { - mql.removeListener(updateCurrentOptions); - }); + mediaQueryListeners.forEach((mql) => mql.removeListener(updateCurrentOptions)); } if (!window.matchMedia) { throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; } else if (responsiveOptions) { - - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); + responsiveOptions.forEach((responsiveOption) => { + const mql = window.matchMedia(responsiveOption[0]); mql.addListener(updateCurrentOptions); mediaQueryListeners.push(mql); - } + }); } // Execute initially without an event argument so we get the correct options updateCurrentOptions(); return { - removeMediaQueryListeners: removeMediaQueryListeners, - getCurrentOptions: function getCurrentOptions() { + removeMediaQueryListeners, + getCurrentOptions() { return extend({}, currentOptions); } }; diff --git a/src/event/event-emitter.js b/src/event/event-emitter.js index c00bcf09..d75966eb 100644 --- a/src/event/event-emitter.js +++ b/src/event/event-emitter.js @@ -48,16 +48,12 @@ export class EventEmitter { emit(event, data) { // Only do something if there are event handlers with this name existing if(this.handlers[event]) { - this.handlers[event].forEach(function(handler) { - handler(data); - }); + this.handlers[event].forEach((handler) => handler(data)); } // Emit event to star event handlers if(this.handlers['*']) { - this.handlers['*'].forEach(function(starHandler) { - starHandler(event, data); - }); + this.handlers['*'].forEach((starHandler) => starHandler(event, data)); } } } diff --git a/src/interpolation/cardinal.js b/src/interpolation/cardinal.js index 2c51abab..ae501000 100644 --- a/src/interpolation/cardinal.js +++ b/src/interpolation/cardinal.js @@ -25,20 +25,20 @@ import {none} from './none'; * @return {Function} */ export function cardinal(options) { - var defaultOptions = { + const defaultOptions = { tension: 1, fillHoles: false }; options = extend({}, defaultOptions, options); - var t = Math.min(1, Math.max(0, options.tension)), - c = 1 - t; + const t = Math.min(1, Math.max(0, options.tension)); + const c = 1 - t; return function cardinal(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts - var segments = splitIntoSegments(pathCoordinates, valueData, { + const segments = splitIntoSegments(pathCoordinates, valueData, { fillHoles: options.fillHoles }); @@ -48,13 +48,11 @@ export function cardinal(options) { } else if(segments.length > 1) { // If the split resulted in more that one segment we need to interpolate each segment individually and join them // afterwards together into a single path. - var paths = []; // For each segment we will recurse the cardinal function - segments.forEach(function(segment) { - paths.push(cardinal(segment.pathCoordinates, segment.valueData)); - }); // Join the segment path data into a single path and return - return SvgPath.join(paths); + return SvgPath.join( + segments.map((segment) => cardinal(segment.pathCoordinates, segment.valueData)) + ); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first // segment @@ -66,29 +64,30 @@ export function cardinal(options) { return none()(pathCoordinates, valueData); } - var path = new SvgPath().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), - z; + const path = new SvgPath().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); + let z; - for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { - var p = [ + for(let i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { + const p = [ {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} ]; - if (z) { - if (!i) { + + if(z) { + if(!i) { p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; - } else if (iLen - 4 === i) { + } else if(iLen - 4 === i) { p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; - } else if (iLen - 2 === i) { + } else if(iLen - 2 === i) { p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; } } else { - if (iLen - 4 === i) { + if(iLen - 4 === i) { p[3] = p[2]; - } else if (!i) { + } else if(!i) { p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; } } diff --git a/src/interpolation/monotone-cubic.js b/src/interpolation/monotone-cubic.js index 91792330..1bdb069d 100644 --- a/src/interpolation/monotone-cubic.js +++ b/src/interpolation/monotone-cubic.js @@ -26,7 +26,7 @@ import {none} from './none'; * @return {Function} */ export function monotoneCubic(options) { - var defaultOptions = { + const defaultOptions = { fillHoles: false }; @@ -35,7 +35,7 @@ export function monotoneCubic(options) { return function monotoneCubic(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts - var segments = splitIntoSegments(pathCoordinates, valueData, { + const segments = splitIntoSegments(pathCoordinates, valueData, { fillHoles: options.fillHoles, increasingX: true }); @@ -46,13 +46,11 @@ export function monotoneCubic(options) { } else if(segments.length > 1) { // If the split resulted in more that one segment we need to interpolate each segment individually and join them // afterwards together into a single path. - var paths = []; // For each segment we will recurse the monotoneCubic fn function - segments.forEach(function(segment) { - paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData)); - }); // Join the segment path data into a single path and return - return SvgPath.join(paths); + return SvgPath.join( + segments.map((segment) => monotoneCubic(segment.pathCoordinates, segment.valueData)) + ); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first // segment @@ -64,24 +62,22 @@ export function monotoneCubic(options) { return none()(pathCoordinates, valueData); } - var xs = [], - ys = [], - i, - n = pathCoordinates.length / 2, - ms = [], - ds = [], dys = [], dxs = [], - path; + const xs = []; + const ys = []; + const n = pathCoordinates.length / 2; + const ms = []; + const ds = []; + const dys = []; + const dxs = []; // Populate x and y coordinates into separate arrays, for readability - - for(i = 0; i < n; i++) { + for(let i = 0; i < n; i++) { xs[i] = pathCoordinates[i * 2]; ys[i] = pathCoordinates[i * 2 + 1]; } // Calculate deltas and derivative - - for(i = 0; i < n - 1; i++) { + for(let i = 0; i < n - 1; i++) { dys[i] = ys[i + 1] - ys[i]; dxs[i] = xs[i + 1] - xs[i]; ds[i] = dys[i] / dxs[i]; @@ -89,11 +85,10 @@ export function monotoneCubic(options) { // Determine desired slope (m) at each point using Fritsch-Carlson method // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation - ms[0] = ds[0]; ms[n - 1] = ds[n - 2]; - for(i = 1; i < n - 1; i++) { + for(let i = 1; i < n - 1; i++) { if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) { ms[i] = 0; } else { @@ -108,10 +103,9 @@ export function monotoneCubic(options) { } // Now build a path from the slopes + const path = new SvgPath().move(xs[0], ys[0], false, valueData[0]); - path = new SvgPath().move(xs[0], ys[0], false, valueData[0]); - - for(i = 0; i < n - 1; i++) { + for(let i = 0; i < n - 1; i++) { path.curve( // First control point xs[i] + dxs[i] / 3, diff --git a/src/interpolation/none.js b/src/interpolation/none.js index c2e5e6c7..777e728a 100644 --- a/src/interpolation/none.js +++ b/src/interpolation/none.js @@ -19,18 +19,20 @@ import {SvgPath} from '../svg/svg-path'; * @return {Function} */ export function none(options) { - var defaultOptions = { + const defaultOptions = { fillHoles: false }; + options = extend({}, defaultOptions, options); + return function none(pathCoordinates, valueData) { - var path = new SvgPath(); - var hole = true; + const path = new SvgPath(); + let hole = true; - for(var i = 0; i < pathCoordinates.length; i += 2) { - var currX = pathCoordinates[i]; - var currY = pathCoordinates[i + 1]; - var currData = valueData[i / 2]; + for(let i = 0; i < pathCoordinates.length; i += 2) { + const currX = pathCoordinates[i]; + const currY = pathCoordinates[i + 1]; + const currData = valueData[i / 2]; if(getMultiValue(currData.value) !== undefined) { diff --git a/src/interpolation/simple.js b/src/interpolation/simple.js index b3fc806c..bec2b7d8 100644 --- a/src/interpolation/simple.js +++ b/src/interpolation/simple.js @@ -25,23 +25,26 @@ import {SvgPath} from '../svg/svg-path'; * @return {Function} */ export function simple(options) { - var defaultOptions = { + const defaultOptions = { divisor: 2, fillHoles: false }; + options = extend({}, defaultOptions, options); - var d = 1 / Math.max(1, options.divisor); + const d = 1 / Math.max(1, options.divisor); return function simple(pathCoordinates, valueData) { - var path = new SvgPath(); - var prevX, prevY, prevData; + const path = new SvgPath(); + let prevX; + let prevY; + let prevData; - for(var i = 0; i < pathCoordinates.length; i += 2) { - var currX = pathCoordinates[i]; - var currY = pathCoordinates[i + 1]; - var length = (currX - prevX) * d; - var currData = valueData[i / 2]; + for(let i = 0; i < pathCoordinates.length; i += 2) { + const currX = pathCoordinates[i]; + const currY = pathCoordinates[i + 1]; + const length = (currX - prevX) * d; + const currData = valueData[i / 2]; if(currData.value !== undefined) { @@ -64,7 +67,7 @@ export function simple(options) { prevY = currY; prevData = currData; } else if(!options.fillHoles) { - prevX = currX = prevData = undefined; + prevX = prevY = prevData = undefined; } } diff --git a/src/interpolation/step.js b/src/interpolation/step.js index 8fadea0e..2581c50b 100644 --- a/src/interpolation/step.js +++ b/src/interpolation/step.js @@ -22,7 +22,7 @@ import {SvgPath} from '../svg/svg-path'; * @returns {Function} */ export function step(options) { - var defaultOptions = { + const defaultOptions = { postpone: true, fillHoles: false }; @@ -30,14 +30,16 @@ export function step(options) { options = extend({}, defaultOptions, options); return function step(pathCoordinates, valueData) { - var path = new SvgPath(); + const path = new SvgPath(); - var prevX, prevY, prevData; + let prevX; + let prevY; + let prevData; - for (var i = 0; i < pathCoordinates.length; i += 2) { - var currX = pathCoordinates[i]; - var currY = pathCoordinates[i + 1]; - var currData = valueData[i / 2]; + for (let i = 0; i < pathCoordinates.length; i += 2) { + const currX = pathCoordinates[i]; + const currY = pathCoordinates[i + 1]; + const currData = valueData[i / 2]; // If the current point is also not a hole we can draw the step lines if(currData.value !== undefined) { diff --git a/src/svg/svg-path.spec.js b/src/svg/svg-path.spec.js new file mode 100644 index 00000000..ee04d546 --- /dev/null +++ b/src/svg/svg-path.spec.js @@ -0,0 +1,166 @@ +import {SvgPath} from './svg-path'; + +describe('SvgPath', () => { + it('should handle position updates correctly', () => { + const path = new SvgPath(); + expect(path.position()).toBe(0); + expect(path.position(100).position()).toBe(0); + expect(path.position(-1).position()).toBe(0); + + path.pathElements = [1, 2, 3]; + expect(path.position(100).position()).toBe(3); + }); + + it('should add absolute and relative path elements correctly', () => { + const path = new SvgPath() + .move(1, 2) + .move(3, 4, true) + .line(5, 6) + .line(7, 8, true) + .curve(9, 10, 11, 12, 13, 14) + .curve(15, 16, 17, 18, 19, 20, true); + + expect(path.pathElements.length).toBe(6); + expect(path.pathElements).toEqual([ + { command: 'M', x: 1, y: 2 }, + { command: 'm', x: 3, y: 4 }, + { command: 'L', x: 5, y: 6 }, + { command: 'l', x: 7, y: 8 }, + { command: 'C', x1: 9, y1: 10, x2: 11, y2: 12, x: 13, y: 14 }, + { command: 'c', x1: 15, y1: 16, x2: 17, y2: 18, x: 19, y: 20 } + ]); + }); + + it('should insert new elements at correct position', () => { + const path = new SvgPath() + .move(1, 2) + .move(7, 8) + .move(9, 10) + .position(1) + .move(3, 4) + .move(5, 6) + .position(100000) + .move(11, 12) + .position(-100000) + .move(-1, 0); + + expect(path.pathElements.length).toBe(7); + expect(path.pathElements).toEqual([ + { command: 'M', x: -1, y: 0 }, + { command: 'M', x: 1, y: 2 }, + { command: 'M', x: 3, y: 4 }, + { command: 'M', x: 5, y: 6 }, + { command: 'M', x: 7, y: 8 }, + { command: 'M', x: 9, y: 10 }, + { command: 'M', x: 11, y: 12 } + ]); + }); + + it('should stringify simple shape correctly', () => { + const path = new SvgPath(true).move(10, 10).line(10, 100).line(100, 100).line(100, 10); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10Z'); + }); + + it('should stringify with configured precision', () => { + const path = new SvgPath(false, { + accuracy: 2 + }).move(10.12345, 10.14345).line(10.14545, 10).line(10.14000000645, 10.3333333333); + expect(path.stringify()).toEqual('M10.12,10.14L10.15,10L10.14,10.33'); + }); + + it('should parse Chartist SVG path style correctly', () => { + const path = new SvgPath().parse('M10,10L10,100L100,100L100,10'); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10'); + }); + + it('should parse MDN SVG path style correctly', () => { + const path = new SvgPath().parse('M10 10 L 10 100 L 100 100 L 100 10 C 1 1, 1 1, 1 1'); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10C1,1,1,1,1,1'); + }); + + it('should parse path with closing command', () => { + const path = new SvgPath().parse('M10 10 L 10 100 L 100 100 L 100 10 C 1 1, 1 1, 1 1 Z'); + expect(path.stringify()).toEqual('M10,10L10,100L100,100L100,10C1,1,1,1,1,1'); + }); + + it('should parse complex path correctly', () => { + const path = new SvgPath(false, { + accuracy: false + }).parse('M7.566371681415929,313.5870318472049L15.132743362831858,322.1479887268699L22.699115044247787,292.49058976570063L30.265486725663717,284.9469379116152L37.83185840707964,277.62070141556273L45.39823008849557,285.4043086222666L52.9646017699115,295.16905806058617L60.530973451327434,288.5395967440654L68.09734513274336,282.3023155078293L75.66371681415929,276.9420221519757L83.23008849557522,271.31296300227655L90.79646017699115,273.1827546735411L98.36283185840708,282.72148250847295L105.929203539823,276.55760703185683L113.49557522123892,278.16318930715545L121.06194690265487,279.67913384762466L128.6283185840708,296.53529757775897L136.1946902654867,324.4003397770142L143.76106194690263,317.1376004332516L151.32743362831857,323.3390406432677L158.89380530973452,328.5597479599146L166.46017699115043,329.67851354926904L174.02654867256635,327.71837583373326L181.5929203539823,335.05972598190976L189.15929203539824,334.29372633331286L196.72566371681415,332.68724934321176L204.29203539823007,330.6752327006325L211.858407079646,325.971917329413L219.42477876106196,328.13057177790404L226.99115044247785,309.6546479835954L234.5575221238938,310.6637826993739L242.12389380530973,310.65221523366176L249.69026548672568,318.40285733188773L257.2566371681416,298.18154267575227L264.8230088495575,307.4788389000347L272.3893805309734,304.189264255087L279.95575221238937,289.0288876874009L287.52212389380526,300.20654714775424L295.0884955752212,298.0164127652739L302.65486725663715,287.69192345832175L310.2212389380531,293.1860711045035L317.78761061946904,300.4760502113585L325.3539823008849,297.94852206276937L332.92035398230087,305.6594311405378L340.4867256637168,306.7859423144216L348.0530973451327,275.68998851331963L355.61946902654864,286.5550640745874L363.1858407079646,288.4952543187362L370.75221238938053,290.1896066608983L378.3185840707965,277.8447927515142L385.88495575221236,282.46018876596827L393.4513274336283,261.617847596371L401.01769911504425,265.06101027918726L408.58407079646014,264.60492966286677L416.1504424778761,252.35288845280365L423.716814159292,239.29220756750195L431.283185840708,229.73170018586225L438.8495575221239,224.1580859168795L446.41592920353986,217.20551113129414L453.9823008849557,212.63435660265037L461.54867256637164,210.4425212857057L469.1150442477876,201.0077146146342L476.6814159292035,182.3934004122068L484.24778761061947,176.98732946386616L491.8141592920354,175.3660655079267L499.38053097345136,181.1589144624976L506.9469026548673,172.81581557677976L514.5132743362832,177.82343674256106L522.079646017699,183.5573714672562L529.646017699115,184.4980688436067L537.2123893805309,201.60789339862924L544.7787610619469,193.42268767053048L552.3451327433628,209.9219909677575L559.9115044247787,221.1318944868172L567.4778761061947,222.47350026973174L575.0442477876105,229.94061399967882L582.6106194690265,213.57676800697396L590.1769911504424,232.97280246785252L597.7433628318583,232.8915724787845L605.3097345132743,231.486089735319L612.8761061946902,234.26534000120475L620.4424778761062,219.90951817170736L628.0088495575221,214.36149678900725L635.5752212389381,204.7245641444236L643.1415929203539,205.04759319834227L650.7079646017698,178.61624621480792L658.2743362831858,174.30656351022486L665.8407079646017,194.06864637030463L673.4070796460177,191.38404795482728L680.9734513274336,188.88380371217903L688.5398230088496,182.47430260433697L696.1061946902654,192.70175438596493L703.6725663716813,182.37945067166908L711.2389380530973,163.80499447227572L718.8053097345132,157.4839718811134L726.3716814159292,149.57403342725343L733.9380530973451,142.6076734278762L741.5044247787611,144.9954413314636L749.070796460177,152.29112878815386L756.637168141593,150.02544379977235L764.2035398230088,139.40203164917125L771.7699115044247,149.22935357717972L779.3362831858407,155.78116263659354L786.9026548672566,145.09966219897575L794.4690265486726,157.52407467202426L802.0353982300885,147.01645902195105L809.6017699115044,141.8658056183404L817.1681415929203,134.36135158737966L824.7345132743362,127.49269525433283L832.3008849557522,120.25886939571154L839.8672566371681,118.26230310074709L847.433628318584,98.76959064327474'); + expect(path.stringify()).toEqual('M7.566371681415929,313.5870318472049L15.132743362831858,322.1479887268699L22.699115044247787,292.49058976570063L30.265486725663717,284.9469379116152L37.83185840707964,277.62070141556273L45.39823008849557,285.4043086222666L52.9646017699115,295.16905806058617L60.530973451327434,288.5395967440654L68.09734513274336,282.3023155078293L75.66371681415929,276.9420221519757L83.23008849557522,271.31296300227655L90.79646017699115,273.1827546735411L98.36283185840708,282.72148250847295L105.929203539823,276.55760703185683L113.49557522123892,278.16318930715545L121.06194690265487,279.67913384762466L128.6283185840708,296.53529757775897L136.1946902654867,324.4003397770142L143.76106194690263,317.1376004332516L151.32743362831857,323.3390406432677L158.89380530973452,328.5597479599146L166.46017699115043,329.67851354926904L174.02654867256635,327.71837583373326L181.5929203539823,335.05972598190976L189.15929203539824,334.29372633331286L196.72566371681415,332.68724934321176L204.29203539823007,330.6752327006325L211.858407079646,325.971917329413L219.42477876106196,328.13057177790404L226.99115044247785,309.6546479835954L234.5575221238938,310.6637826993739L242.12389380530973,310.65221523366176L249.69026548672568,318.40285733188773L257.2566371681416,298.18154267575227L264.8230088495575,307.4788389000347L272.3893805309734,304.189264255087L279.95575221238937,289.0288876874009L287.52212389380526,300.20654714775424L295.0884955752212,298.0164127652739L302.65486725663715,287.69192345832175L310.2212389380531,293.1860711045035L317.78761061946904,300.4760502113585L325.3539823008849,297.94852206276937L332.92035398230087,305.6594311405378L340.4867256637168,306.7859423144216L348.0530973451327,275.68998851331963L355.61946902654864,286.5550640745874L363.1858407079646,288.4952543187362L370.75221238938053,290.1896066608983L378.3185840707965,277.8447927515142L385.88495575221236,282.46018876596827L393.4513274336283,261.617847596371L401.01769911504425,265.06101027918726L408.58407079646014,264.60492966286677L416.1504424778761,252.35288845280365L423.716814159292,239.29220756750195L431.283185840708,229.73170018586225L438.8495575221239,224.1580859168795L446.41592920353986,217.20551113129414L453.9823008849557,212.63435660265037L461.54867256637164,210.4425212857057L469.1150442477876,201.0077146146342L476.6814159292035,182.3934004122068L484.24778761061947,176.98732946386616L491.8141592920354,175.3660655079267L499.38053097345136,181.1589144624976L506.9469026548673,172.81581557677976L514.5132743362832,177.82343674256106L522.079646017699,183.5573714672562L529.646017699115,184.4980688436067L537.2123893805309,201.60789339862924L544.7787610619469,193.42268767053048L552.3451327433628,209.9219909677575L559.9115044247787,221.1318944868172L567.4778761061947,222.47350026973174L575.0442477876105,229.94061399967882L582.6106194690265,213.57676800697396L590.1769911504424,232.97280246785252L597.7433628318583,232.8915724787845L605.3097345132743,231.486089735319L612.8761061946902,234.26534000120475L620.4424778761062,219.90951817170736L628.0088495575221,214.36149678900725L635.5752212389381,204.7245641444236L643.1415929203539,205.04759319834227L650.7079646017698,178.61624621480792L658.2743362831858,174.30656351022486L665.8407079646017,194.06864637030463L673.4070796460177,191.38404795482728L680.9734513274336,188.88380371217903L688.5398230088496,182.47430260433697L696.1061946902654,192.70175438596493L703.6725663716813,182.37945067166908L711.2389380530973,163.80499447227572L718.8053097345132,157.4839718811134L726.3716814159292,149.57403342725343L733.9380530973451,142.6076734278762L741.5044247787611,144.9954413314636L749.070796460177,152.29112878815386L756.637168141593,150.02544379977235L764.2035398230088,139.40203164917125L771.7699115044247,149.22935357717972L779.3362831858407,155.78116263659354L786.9026548672566,145.09966219897575L794.4690265486726,157.52407467202426L802.0353982300885,147.01645902195105L809.6017699115044,141.8658056183404L817.1681415929203,134.36135158737966L824.7345132743362,127.49269525433283L832.3008849557522,120.25886939571154L839.8672566371681,118.26230310074709L847.433628318584,98.76959064327474'); + }); + + it('should scale path along both axes', () => { + const path = new SvgPath() + .move(1, 2) + .line(3, 4) + .curve(5, 6, 7, 8, 9, 10) + .scale(10, 100); + + expect(path.pathElements).toEqual([ + { command: 'M', x: 10, y: 200 }, + { command: 'L', x: 30, y: 400 }, + { command: 'C', x1: 50, y1: 600, x2: 70, y2: 800, x: 90, y: 1000 } + ]); + }); + + it('should translate path along both axes', () => { + const path = new SvgPath() + .move(1, 2) + .line(3, 4) + .curve(5, 6, 7, 8, 9, 10) + .translate(10, 100); + + expect(path.pathElements).toEqual([ + { command: 'M', x: 11, y: 102 }, + { command: 'L', x: 13, y: 104 }, + { command: 'C', x1: 15, y1: 106, x2: 17, y2: 108, x: 19, y: 110 } + ]); + }); + + it('should transform path correctly with custom function', () => { + const path = new SvgPath() + .move(1, 2) + .line(3, 4) + .curve(5, 6, 7, 8, 9, 10) + .transform((element, paramName, elementIndex, paramIndex) => { + if(paramIndex > 3) { + return 0; + } else if(paramName[0] === 'y') { + return 100; + } + }); + + expect(path.pathElements).toEqual([ + { command: 'M', x: 1, y: 100 }, + { command: 'L', x: 3, y: 100 }, + { command: 'C', x1: 5, y1: 100, x2: 7, y2: 100, x: 0, y: 0 } + ]); + }); + + it('should split correctly by move command', () => { + const paths = new SvgPath().parse('M0,0L0,0L0,0L0,0M0,0L0,0L0,0L0,0').splitByCommand('M'); + expect(paths.length).toBe(2); + expect(paths[0].pathElements[0].command).toBe('M'); + expect(paths[0].pathElements.length).toBe(4); + expect(paths[1].pathElements[0].command).toBe('M'); + expect(paths[1].pathElements.length).toBe(4); + }); + + it('should split correctly by move command and tailing move element', () => { + const paths = new SvgPath().parse('M0,0L0,0L0,0L0,0M0,0L0,0L0,0L0,0M0,0').splitByCommand('M'); + expect(paths.length).toBe(3); + expect(paths[2].pathElements[0].command).toBe('M'); + }); + + it('should split correctly by move command and leading other commands', () => { + const paths = new SvgPath().parse('L0,0C0,0,0,0,0,0M0,0L0,0L0,0L0,0M0,0L0,0L0,0L0,0').splitByCommand('M'); + expect(paths.length).toBe(3); + expect(paths[0].pathElements.length).toBe(2); + expect(paths[0].pathElements[0].command).toBe('L'); + expect(paths[0].pathElements[1].command).toBe('C'); + + expect(paths[1].pathElements.length).toBe(4); + expect(paths[1].pathElements[0].command).toBe('M'); + }); +}); diff --git a/src/svg/svg.js b/src/svg/svg.js index cc605f06..4a603404 100644 --- a/src/svg/svg.js +++ b/src/svg/svg.js @@ -38,7 +38,7 @@ export class Svg { } if(parent) { - if (insertFirst && parent._node.firstChild) { + if(insertFirst && parent._node.firstChild) { parent._node.insertBefore(this._node, parent._node.firstChild); } else { parent._node.appendChild(this._node); @@ -69,7 +69,7 @@ export class Svg { return; } - if (key.indexOf(':') !== -1) { + if(key.indexOf(':') !== -1) { var namespacedAttribute = key.split(':'); this._node.setAttributeNS(namespaces[namespacedAttribute[0]], key, attributes[key]); } else { @@ -111,7 +111,7 @@ export class Svg { * @return {Svg} The root SVG element wrapped in a Svg element */ root() { - var node = this._node; + let node = this._node; while(node.nodeName !== 'svg') { node = node.parentNode; } @@ -126,7 +126,7 @@ export class Svg { * @return {Svg} The SVG wrapper for the element found or null if no element was found */ querySelector(selector) { - var foundNode = this._node.querySelector(selector); + const foundNode = this._node.querySelector(selector); return foundNode ? new Svg(foundNode) : null; } @@ -138,7 +138,7 @@ export class Svg { * @return {SvgList} The SVG wrapper list for the element found or null if no element was found */ querySelectorAll(selector) { - var foundNodes = this._node.querySelectorAll(selector); + const foundNodes = this._node.querySelectorAll(selector); return foundNodes.length ? new SvgList(foundNodes) : null; } @@ -166,7 +166,7 @@ export class Svg { // If content is string then we convert it to DOM // TODO: Handle case where content is not a string nor a DOM Node if(typeof content === 'string') { - var container = document.createElement('div'); + const container = document.createElement('div'); container.innerHTML = content; content = container.firstChild; } @@ -176,7 +176,7 @@ export class Svg { // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) - var fnObj = this.elem('foreignObject', attributes, className, insertFirst); + const fnObj = this.elem('foreignObject', attributes, className, insertFirst); // Add content to foreignObjectElement fnObj._node.appendChild(content); @@ -203,7 +203,7 @@ export class Svg { * @return {Svg} The same wrapper object that got emptied */ empty() { - while (this._node.firstChild) { + while(this._node.firstChild) { this._node.removeChild(this._node.firstChild); } @@ -288,11 +288,10 @@ export class Svg { * @return {Svg} The wrapper of the current element */ removeClass(names) { - var removedClasses = names.trim().split(/\s+/); + const removedClasses = names.trim().split(/\s+/); - this._node.setAttribute('class', this.classes().filter(function(name) { - return removedClasses.indexOf(name) === -1; - }).join(' ')); + this._node.setAttribute('class', + this.classes().filter((name) => removedClasses.indexOf(name) === -1).join(' ')); return this; } @@ -374,13 +373,12 @@ export class Svg { guided = true; } - Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + Object.keys(animations).forEach((attribute) => { - function createAnimate(animationDefinition, guided) { - var attributeProperties = {}, - animate, - timeout, - animationEasing; + const createAnimate = (animationDefinition, guided) => { + const attributeProperties = {}; + let animationEasing; + let timeout; // Check if an easing is specified in the definition object and delete it from the object as it will not // be part of the animate element attributes. @@ -415,15 +413,15 @@ export class Svg { animationDefinition.begin = 'indefinite'; } - animate = this.elem('animate', extend({ + const animate = this.elem('animate', extend({ attributeName: attribute }, animationDefinition)); if(guided) { // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout - setTimeout(function() { + setTimeout(() => { // If beginElement fails we set the animated attribute to the end position and remove the animate element - // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in + // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occurred in // the browser. (Currently FF 34 does not support animate elements in foreignObjects) try { animate._node.beginElement(); @@ -434,20 +432,20 @@ export class Svg { // Remove the animate element as it's no longer required animate.remove(); } - }.bind(this), timeout); + }, timeout); } if(eventEmitter) { - animate._node.addEventListener('beginEvent', function handleBeginEvent() { + animate._node.addEventListener('beginEvent', () => eventEmitter.emit('animationBegin', { element: this, animate: animate._node, params: animationDefinition - }); - }.bind(this)); + }) + ); } - animate._node.addEventListener('endEvent', function handleEndEvent() { + animate._node.addEventListener('endEvent', () => { if(eventEmitter) { eventEmitter.emit('animationEnd', { element: this, @@ -463,19 +461,17 @@ export class Svg { // Remove the animate element as it's no longer required animate.remove(); } - }.bind(this)); - } + }); + }; // If current attribute is an array of definition objects we create an animate for each and disable guided mode if(animations[attribute] instanceof Array) { - animations[attribute].forEach(function(animationDefinition) { - createAnimate.bind(this)(animationDefinition, false); - }.bind(this)); + animations[attribute] + .forEach((animationDefinition) => createAnimate(animationDefinition, false)); } else { - createAnimate.bind(this)(animations[attribute], guided); + createAnimate(animations[attribute], guided); } - - }.bind(this)); + }); return this; } diff --git a/src/svg/svg.spec.js b/src/svg/svg.spec.js new file mode 100644 index 00000000..f71b3efe --- /dev/null +++ b/src/svg/svg.spec.js @@ -0,0 +1,165 @@ +import {Svg} from './svg'; +import {namespaces} from '../core/globals'; + +describe('Svg', () => { + it('should create a valid svg dom element', () => { + const svg = new Svg('svg'); + + expect(svg).toBeDefined(); + expect(svg._node).toBeDefined(); + expect(svg._node.nodeName.toLowerCase()).toBe('svg'); + }); + + it('should create a valid svg dom element with attributes', () => { + const svg = new Svg('svg', { + width: '100%', + height: '100%' + }); + + expect(svg).toBeDefined(); + expect(svg._node).toBeDefined(); + expect(svg._node.nodeName.toLowerCase()).toBe('svg'); + expect(svg._node.attributes.width.textContent).toBe('100%'); + expect(svg._node.attributes.height.textContent).toBe('100%'); + }); + + it('should create nested objects with attributes', () => { + const svg = new Svg('svg'); + svg.elem('g').elem('g').elem('circle', { + cx: 100, + cy: 100, + r: 10 + }); + + expect(svg._node).toBeDefined(); + expect(svg._node.firstChild.firstChild.firstChild).toBeDefined(); + expect(svg._node.firstChild.firstChild.firstChild.attributes.cx.textContent).toBe('100'); + expect(svg._node.firstChild.firstChild.firstChild.attributes.cy.textContent).toBe('100'); + expect(svg._node.firstChild.firstChild.firstChild.attributes.r.textContent).toBe('10'); + }); + + it('should allow to set attributes manually', () => { + const svg = new Svg('svg'); + svg.elem('circle').attr({ + cx: 100, + cy: 100, + r: 10 + }); + + expect(svg._node).toBeDefined(); + expect(svg._node.firstChild).toBeDefined(); + expect(svg._node.firstChild.attributes.cx.textContent).toBe('100'); + expect(svg._node.firstChild.attributes.cy.textContent).toBe('100'); + expect(svg._node.firstChild.attributes.r.textContent).toBe('10'); + }); + + it('should allow to set namespaced attributes', () => { + const svg = new Svg('image'); + svg.elem('image').attr({ + x: 100, + y: 100, + height: 100, + width: 100, + 'xlink:href': 'image.jpg' + }); + + expect(svg._node).toBeDefined(); + expect(svg._node.firstChild).toBeDefined(); + expect(svg._node.firstChild.getAttribute('x')).toBe('100'); + expect(svg._node.firstChild.getAttribute('y')).toBe('100'); + expect(svg._node.firstChild.getAttribute('width')).toBe('100'); + expect(svg._node.firstChild.getAttribute('height')).toBe('100'); + expect(svg._node.firstChild.getAttributeNS(namespaces.xlink, 'href')).toBe('image.jpg'); + }); + + it('should clear on each nesting level', () => { + const svg = new Svg('svg'); + const group = svg.elem('g'); + group.elem('circle'); + group.elem('circle'); + group.elem('circle'); + + expect(svg._node).toBeDefined(); + expect(svg._node.firstChild.childNodes.length).toBe(3); + + group.empty(); + expect(svg._node.firstChild.childNodes.length).toBe(0); + + svg.empty(); + expect(svg._node.firstChild).toBeNull(); + }); + + it('should allow to remove a certain element', () => { + const svg = new Svg('svg'); + const text = svg.elem('text'); + + expect(svg._node).toBeDefined(); + expect(svg._node.childNodes.length).toBe(1); + expect(svg._node.firstChild.nodeName.toLowerCase()).toBe('text'); + + text.remove(); + expect(svg._node.childNodes.length).toBe(0); + }); + + it('should allow to write text content into elements', () => { + const svg = new Svg('svg'); + svg.elem('text').text('Hello World'); + + expect(svg._node).toBeDefined(); + expect(svg._node.childNodes.length).toBe(1); + expect(svg._node.firstChild.nodeName.toLowerCase()).toBe('text'); + expect(svg._node.firstChild.firstChild.nodeType).toBe(3); + expect(svg._node.firstChild.firstChild.textContent).toBe('Hello World'); + }); + + it('should allow to add and remove classes on elements', () => { + const svg = new Svg('svg') + .addClass('test-class-1') + .addClass('test-class-2') + // Should not allow duplicates + .addClass('test-class-2') + // Should allow multiple classes with white spaces + .addClass('test-class-3 test-class-4'); + + expect(svg._node).toBeDefined(); + expect(svg._node.getAttribute('class').split(' ')).toEqual([ + 'test-class-1', + 'test-class-2', + 'test-class-3', + 'test-class-4' + ]); + + svg.removeClass('test-class-1'); + // Should allow multiple classes with whitespaces + svg.removeClass('test-class-2 test-class-3'); + + expect(svg._node.getAttribute('class')).toBe('test-class-4'); + }); + + it('should allow to travers up in the fluent API chain and set attributes on the way', () => { + const svg = new Svg('svg'); + svg.elem('g').elem('g').elem('g').elem('circle').parent().attr({ + transform: 'rotate(10 10 10)' + }).parent().attr({ + transform: 'rotate(20 20 20)' + }).parent().attr({ + transform: 'rotate(30 30 30)' + }).parent().attr({ + width: '100%', + height: '100%' + }); + + expect(svg._node).toBeDefined(); + expect(svg._node.attributes.width.textContent).toBe('100%'); + expect(svg._node.attributes.height.textContent).toBe('100%'); + + expect(svg._node.firstChild).toBeDefined(); + expect(svg._node.firstChild.attributes.transform.textContent).toBe('rotate(30 30 30)'); + + expect(svg._node.firstChild.firstChild).toBeDefined(); + expect(svg._node.firstChild.firstChild.attributes.transform.textContent).toBe('rotate(20 20 20)'); + + expect(svg._node.firstChild.firstChild.firstChild).toBeDefined(); + expect(svg._node.firstChild.firstChild.firstChild.attributes.transform.textContent).toBe('rotate(10 10 10)'); + }); +}); From ebaf247dc4afbcc1b67e5a37ae7ddcfe04a9c2a1 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 28 Oct 2016 02:35:16 +0200 Subject: [PATCH 456/593] chore(linting): Added linter and fixed linting issues --- .eslintrc | 224 +++++++++ dist/chartist.esm.js | 711 +++++++++++++++------------- dist/chartist.esm.js.map | 2 +- dist/chartist.umd.js | 8 +- dist/chartist.umd.js.map | 2 +- package.json | 19 +- src/axes/axis.js | 2 +- src/axes/axis.spec.js | 6 +- src/charts/bar.js | 4 +- src/charts/bar.spec.js | 8 +- src/charts/line.js | 25 +- src/charts/line.spec.js | 30 +- src/charts/pie.js | 38 +- src/charts/pie.spec.js | 2 +- src/core/creation.js | 14 +- src/core/creation.spec.js | 2 +- src/core/data.js | 16 +- src/core/functional.js | 10 +- src/core/lang.js | 4 +- src/core/math.js | 6 +- src/core/options-provider.js | 8 +- src/interpolation/cardinal.js | 4 +- src/interpolation/monotone-cubic.js | 4 +- src/interpolation/none.js | 2 +- src/interpolation/simple.js | 2 +- src/interpolation/step.js | 4 +- src/styles/chartist.scss | 2 +- src/svg/svg-list.js | 42 +- src/svg/svg-path.js | 82 ++-- src/svg/svg-path.spec.js | 44 +- src/svg/svg.js | 10 +- src/testing/fixtures.js | 12 +- src/testing/jasmine-dom-matchers.js | 3 - yarn.lock | 507 +++++++++++++++++++- 34 files changed, 1310 insertions(+), 549 deletions(-) create mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..a667cd4d --- /dev/null +++ b/.eslintrc @@ -0,0 +1,224 @@ +{ + "parser": "babel-eslint", + + "parser-options": { + "ecmaFeatures": { + "binaryLiterals": false, + "blockBindings": false, + "defaultParams": true, + "forOf": false, + "generators": false, + "objectLiteralComputedProperties": true, + "objectLiteralDuplicateProperties": false, + "objectLiteralShorthandMethods": true, + "objectLiteralShorthandProperties": true, + "octalLiterals": false, + "regexUFlag": false, + "regexYFlag": false, + "templateStrings": true, + "unicodeCodePointEscapes": false, + "jsx": false, + "spread": true, + "arrowFunctions": true, + "classes": true, + "modules": true, + "restParams": true, + "destructuring": true + } + }, + "env": { + "browser": true, + "node": false, + "amd": false, + "mocha": false, + "jasmine": true , + "phantomjs": false, + "jquery": false, + "prototypejs": false, + "shelljs": false + }, + + "globals": { + + }, + + "plugins": [ + + ], + + "rules": { + + + "no-comma-dangle": 0, + "no-cond-assign": 0, + "no-console": 2, + "no-constant-condition": 0, + "no-control-regex": 0, + "no-debugger": 2, + "no-dupe-keys": 0, + "no-empty": 0, + "no-empty-class": 0, + "no-ex-assign": 0, + "no-extra-boolean-cast": 0, + "no-extra-parens": 0, + "no-extra-semi": 0, + "no-func-assign": 0, + "no-inner-declarations": 0, + "no-invalid-regexp": 0, + "no-irregular-whitespace": 0, + "no-negated-in-lhs": 0, + "no-obj-calls": 0, + "no-regex-spaces": 0, + "no-reserved-keys": 0, + "no-sparse-arrays": 0, + "no-unreachable": 2, + "use-isnan": 0, + "valid-jsdoc": 0, + "valid-typeof": 0, + + + + + "block-scoped-var": 0, + "complexity": 0, + "consistent-return": 0, + "curly": 2, + "default-case": 0, + "dot-notation": 1, + "eqeqeq": 2, + "guard-for-in": 0, + "no-alert": 2, + "no-caller": 2, + "no-div-regex": 0, + "no-else-return": 0, + "no-empty-label": 0, + "no-eq-null": 0, + "no-eval": 2, + "no-extend-native": 0, + "no-extra-bind": 2, + "no-fallthrough": 0, + "no-floating-decimal": 0, + "no-implied-eval": 2, + "no-iterator": 0, + "no-labels": 0, + "no-lone-blocks": 0, + "no-loop-func": 2, + "no-multi-spaces": 2, + "no-multi-str": 0, + "no-native-reassign": 0, + "no-new": 0, + "no-new-func": 0, + "no-new-wrappers": 0, + "no-octal": 0, + "no-octal-escape": 0, + "no-process-env": 0, + "no-proto": 0, + "no-redeclare": 0, + "no-return-assign": 0, + "no-script-url": 0, + "no-self-compare": 0, + "no-sequences": 0, + "no-unused-expressions": 0, + "no-void": 0, + "no-warning-comments": 0, + "no-with": 2, + "radix": 2, + "vars-on-top": 0, + "wrap-iife": 0, + "yoda": 0, + + + + + "global-strict": 0, + "no-extra-strict": 0, + "strict": 0, + + + + + "no-catch-shadow": 0, + "no-delete-var": 0, + "no-label-var": 0, + "no-shadow": 2, + "no-shadow-restricted-names": 2, + "no-undef": 0, + "no-undef-init": 0, + "no-undefined": 0, + "no-unused-vars": 0, + "no-use-before-define": 0, + + + + + "handle-callback-err": 0, + "no-mixed-requires": 0, + "no-new-require": 0, + "no-path-concat": 0, + "no-process-exit": 0, + "no-restricted-modules": 0, + "no-sync": 0, + + + + + "brace-style": ["error", "1tbs"], + "camelcase": 2, + "comma-spacing": 0, + "comma-style": ["error", "last"], + "consistent-this": 0, + "eol-last": 2, + "func-names": 0, + "func-style": 0, + "key-spacing": 2, + "max-nested-callbacks": 0, + "new-cap": 1, + "new-parens": 0, + "no-array-constructor": 2, + "no-inline-comments": 0, + "no-lonely-if": 0, + "no-mixed-spaces-and-tabs": 2, + "no-multiple-empty-lines": 2, + "no-nested-ternary": 2, + "no-new-object": 0, + "semi-spacing": 2, + "no-spaced-func": 2, + "no-ternary": 0, + "no-trailing-spaces": 2, + "no-underscore-dangle": 0, + "no-wrap-func": 0, + "one-var": 0, + "operator-assignment": 0, + "padded-blocks": 0, + "quote-props": 0, + "quotes": ["error", "single"], + "semi": 0, + "sort-vars": 0, + "space-before-function-paren": ["error", "never"], + "keyword-spacing": 0, + "space-before-blocks": 2, + "space-in-brackets": 0, + "space-in-parens": 0, + "space-infix-ops": 0, + "space-return-throw-case": 0, + "space-unary-ops": 0, + "spaced-comment": 1, + "wrap-regex": 0, + + + + + "no-var": 2, + "generator-star": 0, + + + + + "max-depth": 0, + "max-len": 0, + "max-params": 0, + "max-statements": 0, + "no-bitwise": 0, + "no-plusplus": 0 + } +} diff --git a/dist/chartist.esm.js b/dist/chartist.esm.js index cadb6b24..f3b8ca63 100644 --- a/dist/chartist.esm.js +++ b/dist/chartist.esm.js @@ -1,8 +1,8 @@ /* Chartist.js 1.0.0 * Copyright © 2016 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 + * https://raw.githubusercontent.com/chartist-js/chartist/master/LICENSE-WTFPL + * https://raw.githubusercontent.com/chartist-js/chartist/master/LICENSE-MIT */ var version = '1.0.0'; @@ -137,7 +137,10 @@ function quantity(input) { unit: match[2] || undefined }; } - return { value: input }; + + return { + value: input + }; } /** @@ -152,6 +155,16 @@ function alphaNumerate(n) { return String.fromCharCode(97 + n % 26); } +var _toConsumableArray = (function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { + arr2[i] = arr[i]; + }return arr2; + } else { + return Array.from(arr); + } +}); + /** * Helps to simplify functional style code * @@ -159,9 +172,9 @@ function alphaNumerate(n) { * @param {*} n This exact value will be returned by the noop function * @return {*} The same value that was provided to the n parameter */ -function noop(n) { +var noop = function noop(n) { return n; -} +}; /** * Functional style helper to produce array with given length initialized with undefined values @@ -170,9 +183,9 @@ function noop(n) { * @param length * @return {Array} */ -function times(length) { - return Array.apply(null, new Array(length)); -} +var times = function times(length) { + return Array.from({ length: length }); +}; /** * Sum helper to be used in reduce functions @@ -182,60 +195,40 @@ function times(length) { * @param current * @return {*} */ -function sum(previous, current) { +var sum = function sum(previous, current) { return previous + (current ? current : 0); -} +}; /** - * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor. + * 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). * - * @memberof Chartist.Core - * @param {Number} factor - * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array - */ -function mapMultiply(factor) { - return function (num) { - return num * factor; - }; -} - -/** - * Add helper to be used in `Array.map` for adding a addend to each value of an array. + * For example: + * @example + * ```javascript + * const data = [[1, 2], [3], []]; + * serialMap(data, cb); * - * @memberof Chartist.Core - * @param {Number} addend - * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array - */ -function mapAdd(addend) { - return function (num) { - return num + addend; - }; -} - -/** - * 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). + * // where cb will be called 2 times + * // 1. call arguments: (1, 3, undefined) + * // 2. call arguments: (2, undefined, undefined) + * ``` * * @memberof Chartist.Core - * @param arr - * @param cb + * @param array + * @param callback * @return {Array} */ -function serialMap(arr, cb) { - var result = [], - length = Math.max.apply(null, arr.map(function (e) { - return e.length; - })); - - times(length).forEach(function (e, index) { - var args = arr.map(function (e) { - return e[index]; - }); - - result[index] = cb.apply(null, args); +var serialMap = function serialMap(array, callback) { + return times(Math.max.apply(Math, _toConsumableArray(array.map(function (element) { + return element.length; + })))).map(function (inner, index) { + return callback.apply(undefined, _toConsumableArray(array.map(function (element) { + return element[index]; + }))); }); +}; - return result; -} +var EPSILON = 2.221E-16; /** * Calculate the order of magnitude for the chart scale @@ -270,7 +263,7 @@ function projectLength(axisLength, length, bounds) { * @returns {number} Rounded value */ function roundWithPrecision(value, digits) { - var precision$$1 = Math.pow(10, digits || precision$$1); + var precision$$1 = Math.pow(10, digits || precision); return Math.round(value * precision$$1) / precision$$1; } @@ -298,9 +291,9 @@ function rho(num) { return x * x + 1; } - var x1 = 2, - x2 = 2, - divisor; + var x1 = 2; + var x2 = 2; + var divisor = void 0; if (num % 2 === 0) { return 2; } @@ -341,14 +334,19 @@ function polarToCartesian(centerX, centerY, radius, angleInDegrees) { * @param {Object...} sources This object (objects) will be merged into target and then target is returned * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source */ -function extend(target) { - var i, source, sourceProp; +function extend() { + var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + target = target || {}; - for (i = 1; i < arguments.length; i++) { - source = arguments[i]; + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var source = sources[i]; for (var prop in source) { - sourceProp = source[prop]; + var sourceProp = source[prop]; if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { target[prop] = extend(target[prop], sourceProp); } else { @@ -413,7 +411,9 @@ function deserialize(data) { * @return {Object} The normalized data object */ function normalizeData(data, reverse, multi) { - var labelCount; + var _output$normalized$la; + + var labelCount = void 0; var output = { raw: data, normalized: {} @@ -430,9 +430,9 @@ function normalizeData(data, reverse, multi) { return value instanceof Array; })) { // Getting the series with the the most elements - labelCount = Math.max.apply(null, output.normalized.series.map(function (series) { + labelCount = Math.max.apply(Math, _toConsumableArray(output.normalized.series.map(function (series) { return series.length; - })); + }))); } else { // We're dealing with Pie data so we just take the normalized array length labelCount = output.normalized.series.length; @@ -440,9 +440,9 @@ function normalizeData(data, reverse, multi) { output.normalized.labels = (data.labels || []).slice(); // Padding the labels to labelCount with empty strings - Array.prototype.push.apply(output.normalized.labels, times(Math.max(0, labelCount - output.normalized.labels.length)).map(function () { + (_output$normalized$la = output.normalized.labels).push.apply(_output$normalized$la, _toConsumableArray(times(Math.max(0, labelCount - output.normalized.labels.length)).map(function () { return ''; - })); + }))); if (reverse) { reverseData(output.normalized); @@ -482,11 +482,32 @@ function isDataHoleValue(value) { function reverseData(data) { data.labels.reverse(); data.series.reverse(); - for (var i = 0; i < data.series.length; i++) { - if (typeof data.series[i] === 'object' && data.series[i].data !== undefined) { - data.series[i].data.reverse(); - } else if (data.series[i] instanceof Array) { - data.series[i].reverse(); + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = data.series[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var series = _step.value; + + if (typeof series === 'object' && series.data !== undefined) { + series.data.reverse(); + } else if (series instanceof Array) { + series.reverse(); + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } } } } @@ -552,7 +573,7 @@ function getDataArray(data, reverse, multi) { * @param value */ function isMultiValue(value) { - return typeof value === 'object' && ('x' in value || 'y' in value); + return typeof value === 'object' && (value.hasOwnProperty('x') || value.hasOwnProperty('y')); } /** @@ -561,12 +582,13 @@ function isMultiValue(value) { * @memberof Chartist.Core * @param value * @param dimension - * @param defaultValue * @returns {*} */ -function getMultiValue(value, dimension) { +function getMultiValue(value) { + var dimension = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'y'; + if (isMultiValue(value)) { - return getNumberOrUndefined(value[dimension || 'y']); + return getNumberOrUndefined(value[dimension]); } else { return getNumberOrUndefined(value); } @@ -678,15 +700,15 @@ function getHighLow(data, options, dimension) { var findLow = options.low === undefined; // Function to recursively walk through arrays and find highest and lowest number - function recursiveHighLow(data) { - if (data === undefined) { + function recursiveHighLow(sourceData) { + if (sourceData === undefined) { return undefined; - } else if (data instanceof Array) { - for (var i = 0; i < data.length; i++) { - recursiveHighLow(data[i]); + } else if (sourceData instanceof Array) { + for (var i = 0; i < sourceData.length; i++) { + recursiveHighLow(sourceData[i]); } } else { - var value = dimension ? +data[dimension] : +data; + var value = dimension ? +sourceData[dimension] : +sourceData; if (findHigh && value > highLow.high) { highLow.high = value; @@ -744,11 +766,7 @@ function getHighLow(data, options, dimension) { * @return {Object} All the values to set the bounds of the chart */ function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { - var i, - optimizationCounter = 0, - newMin, - newMax, - bounds = { + var bounds = { high: highLow.high, low: highLow.low }; @@ -777,6 +795,7 @@ function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { bounds.step = smallestFactor; } else { // Trying to divide or multiply by 2 and find the best step value + var optimizationCounter = 0; while (true) { if (scaleUp && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { bounds.step *= 2; @@ -796,7 +815,6 @@ function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { } } - var EPSILON = 2.221E-16; bounds.step = Math.max(bounds.step, EPSILON); function safeIncrement(value, increment) { // If increment is too small use *= (1+EPSILON) as a simple nextafter @@ -807,8 +825,8 @@ function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { } // Narrow min and max based on new step - newMin = bounds.min; - newMax = bounds.max; + var newMin = bounds.min; + var newMax = bounds.max; while (newMin + bounds.step <= bounds.low) { newMin = safeIncrement(newMin, bounds.step); } @@ -820,13 +838,14 @@ function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { bounds.range = bounds.max - bounds.min; var values = []; - for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { + for (var i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { var value = roundWithPrecision(i); if (value !== values[values.length - 1]) { - values.push(i); + values.push(value); } } bounds.values = values; + return bounds; } @@ -863,6 +882,8 @@ var _createClass = (function () { * @constructor */ var SvgList = function SvgList(nodeList) { + var _arguments = arguments; + _classCallCheck(this, SvgList); var list = this; @@ -877,9 +898,9 @@ var SvgList = function SvgList(nodeList) { return ['constructor', 'parent', 'querySelector', 'querySelectorAll', 'replace', 'append', 'classes', 'height', 'width'].indexOf(prototypeProperty) === -1; }).forEach(function (prototypeProperty) { list[prototypeProperty] = function () { - var args = Array.prototype.slice.call(arguments, 0); + var args = Array.from(_arguments); list.svgElements.forEach(function (element) { - Svg.prototype[prototypeProperty].apply(element, args); + return Svg.prototype[prototypeProperty].apply(element, args); }); return list; }; @@ -1313,17 +1334,18 @@ var Svg = function () { }, { key: 'animate', value: function animate(animations, guided, eventEmitter) { + var _this = this; + if (guided === undefined) { guided = true; } - Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { + Object.keys(animations).forEach(function (attribute) { - function createAnimate(animationDefinition, guided) { - var attributeProperties = {}, - animate, - timeout, - animationEasing; + var createAnimate = function createAnimate(animationDefinition, createGuided) { + var attributeProperties = {}; + var animationEasing = void 0; + var timeout = void 0; // Check if an easing is specified in the definition object and delete it from the object as it will not // be part of the animate element attributes. @@ -1344,11 +1366,11 @@ var Svg = function () { } // Adding "fill: freeze" if we are in guided mode and set initial attribute values - if (guided) { + if (createGuided) { animationDefinition.fill = 'freeze'; // Animated property on our element should already be set to the animation from value in guided mode attributeProperties[attribute] = animationDefinition.from; - this.attr(attributeProperties); + _this.attr(attributeProperties); // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin // which needs to be in ms aside @@ -1356,66 +1378,66 @@ var Svg = function () { animationDefinition.begin = 'indefinite'; } - animate = this.elem('animate', extend({ + var animate = _this.elem('animate', extend({ attributeName: attribute }, animationDefinition)); - if (guided) { + if (createGuided) { // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout setTimeout(function () { // If beginElement fails we set the animated attribute to the end position and remove the animate element - // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in + // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occurred in // the browser. (Currently FF 34 does not support animate elements in foreignObjects) try { animate._node.beginElement(); } catch (err) { // Set animated attribute to current animated value attributeProperties[attribute] = animationDefinition.to; - this.attr(attributeProperties); + _this.attr(attributeProperties); // Remove the animate element as it's no longer required animate.remove(); } - }.bind(this), timeout); + }, timeout); } if (eventEmitter) { - animate._node.addEventListener('beginEvent', function handleBeginEvent() { - eventEmitter.emit('animationBegin', { - element: this, + animate._node.addEventListener('beginEvent', function () { + return eventEmitter.emit('animationBegin', { + element: _this, animate: animate._node, params: animationDefinition }); - }.bind(this)); + }); } - animate._node.addEventListener('endEvent', function handleEndEvent() { + animate._node.addEventListener('endEvent', function () { if (eventEmitter) { eventEmitter.emit('animationEnd', { - element: this, + element: _this, animate: animate._node, params: animationDefinition }); } - if (guided) { + if (createGuided) { // Set animated attribute to current animated value attributeProperties[attribute] = animationDefinition.to; - this.attr(attributeProperties); + _this.attr(attributeProperties); // Remove the animate element as it's no longer required animate.remove(); } - }.bind(this)); - } + }); + }; // If current attribute is an array of definition objects we create an animate for each and disable guided mode if (animations[attribute] instanceof Array) { animations[attribute].forEach(function (animationDefinition) { - createAnimate.bind(this)(animationDefinition, false); - }.bind(this)); + return createAnimate(animationDefinition, false); + }); } else { - createAnimate.bind(this)(animations[attribute], guided); + createAnimate(animations[attribute], guided); } - }.bind(this)); + }); return this; } @@ -1477,25 +1499,25 @@ var easings = { * @param {String} className Specify a class to be added to the SVG element * @return {Object} The created/reinitialized SVG element */ -function createSvg(container, width, height, className) { - var svg; - - width = width || '100%'; - height = height || '100%'; +function createSvg(container) { + var width = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '100%'; + var height = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '100%'; + var className = arguments[3]; // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ - Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { + Array.from(container.querySelectorAll('svg')).filter(function (svg) { return svg.getAttributeNS(namespaces.xmlns, 'ct'); - }).forEach(function removePreviousElement(svg) { - container.removeChild(svg); + }).forEach(function (svg) { + return container.removeChild(svg); }); // Create svg object with width and height or use 100% as default - svg = new Svg('svg').attr({ + var svg = new Svg('svg').attr({ width: width, height: height }).addClass(className).attr({ + // TODO: Check better solution (browser support) and remove inline styles due to CSP style: 'width: ' + width + '; height: ' + height + ';' }); @@ -1513,8 +1535,8 @@ function createSvg(container, width, height, className) { * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed * @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. */ -function normalizePadding(padding, fallback) { - fallback = fallback || 0; +function normalizePadding(padding) { + var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return typeof padding === 'number' ? { top: padding, @@ -1661,7 +1683,7 @@ function createGridBackground(gridGroup, chartRect, className, eventEmitter) { * @param eventEmitter */ function createLabel(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { - var labelElement; + var labelElement = void 0; var positionalData = {}; positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; @@ -1672,7 +1694,9 @@ function createLabel(position, length, index, labels, axis, axisOffset, labelOff 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 stepLength = Math.round(positionalData[axis.units.len]); + var stepCounterLength = Math.round(positionalData[axis.counterUnits.len]); + var content = ('\n \n ' + labels[index] + '\n \n ').trim(); labelElement = group.foreignObject(content, extend({ style: 'overflow: visible;' @@ -1701,22 +1725,21 @@ function createLabel(position, length, index, labels, axis, axisOffset, labelOff * @return {Object} The consolidated options object from the defaults, base and matching responsive options */ function optionsProvider(options, responsiveOptions, eventEmitter) { - var baseOptions = extend({}, options), - currentOptions, - mediaQueryListeners = [], - i; + var baseOptions = extend({}, options); + var currentOptions = void 0; + var mediaQueryListeners = []; function updateCurrentOptions(mediaEvent) { var previousOptions = currentOptions; currentOptions = extend({}, baseOptions); if (responsiveOptions) { - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); + responsiveOptions.forEach(function (responsiveOption) { + var mql = window.matchMedia(responsiveOption[0]); if (mql.matches) { - currentOptions = extend(currentOptions, responsiveOptions[i][1]); + currentOptions = extend(currentOptions, responsiveOption[1]); } - } + }); } if (eventEmitter && mediaEvent) { @@ -1729,19 +1752,18 @@ function optionsProvider(options, responsiveOptions, eventEmitter) { function removeMediaQueryListeners() { mediaQueryListeners.forEach(function (mql) { - mql.removeListener(updateCurrentOptions); + return mql.removeListener(updateCurrentOptions); }); } if (!window.matchMedia) { throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; } else if (responsiveOptions) { - - for (i = 0; i < responsiveOptions.length; i++) { - var mql = window.matchMedia(responsiveOptions[i][0]); + responsiveOptions.forEach(function (responsiveOption) { + var mql = window.matchMedia(responsiveOption[0]); mql.addListener(updateCurrentOptions); mediaQueryListeners.push(mql); - } + }); } // Execute initially without an event argument so we get the correct options updateCurrentOptions(); @@ -1817,14 +1839,14 @@ var EventEmitter = function () { // Only do something if there are event handlers with this name existing if (this.handlers[event]) { this.handlers[event].forEach(function (handler) { - handler(data); + return handler(data); }); } // Emit event to star event handlers if (this.handlers['*']) { this.handlers['*'].forEach(function (starHandler) { - starHandler(event, data); + return starHandler(event, data); }); } } @@ -1845,6 +1867,8 @@ var BaseChart = function () { * @constructor */ function BaseChart(query, data, defaultOptions, options, responsiveOptions) { + var _this = this; + _classCallCheck(this, BaseChart); this.container = querySelector$1(query); @@ -1857,9 +1881,9 @@ var BaseChart = function () { this.eventEmitter = new EventEmitter(); this.supportsForeignObject = isSupported('Extensibility'); this.supportsAnimations = isSupported('AnimationEventsAttribute'); - this.resizeListener = function resizeListener() { - this.update(); - }.bind(this); + this.resizeListener = function () { + return _this.update(); + }; if (this.container) { // If chartist was already initialized in this container we are detaching all event listeners first @@ -1872,7 +1896,9 @@ var BaseChart = function () { // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. - this.initializeTimeoutId = setTimeout(this.initialize.bind(this), 0); + this.initializeTimeoutId = setTimeout(function () { + return _this.initialize(); + }, 0); } _createClass(BaseChart, [{ @@ -1983,6 +2009,8 @@ var BaseChart = function () { }, { key: 'initialize', value: function initialize() { + var _this2 = this; + // Add window resize listener that re-creates the chart window.addEventListener('resize', this.resizeListener); @@ -1991,19 +2019,19 @@ var BaseChart = function () { this.optionsProvider = optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); // Register options change listener that will trigger a chart update this.eventEmitter.addEventHandler('optionsChanged', function () { - this.update(); - }.bind(this)); + return _this2.update(); + }); // Before the first chart creation we need to register us with all plugins that are configured // Initialize all relevant plugins with our chart object and the plugin options specified in the config if (this.options.plugins) { this.options.plugins.forEach(function (plugin) { if (plugin instanceof Array) { - plugin[0](this, plugin[1]); + plugin[0](_this2, plugin[1]); } else { - plugin(this); + plugin(_this2); } - }.bind(this)); + }); } // Event for data transformation that allows to manipulate the data before it gets rendered in the charts @@ -2091,6 +2119,8 @@ var Axis = function () { }, { key: 'createGridAndLabels', value: function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) { + var _this = this; + var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; var projectedValues = this.ticks.map(this.projectValue.bind(this)); var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); @@ -2103,7 +2133,7 @@ var Axis = function () { // TODO: Find better solution for solving this problem // Calculate how much space we have available for the label - var labelLength; + var labelLength = void 0; if (projectedValues[index + 1]) { // If we still have one label ahead, we can calculate the distance to the next tick / label labelLength = projectedValues[index + 1] - projectedValue; @@ -2111,48 +2141,48 @@ var Axis = function () { // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will // still be visible inside of the chart padding. - labelLength = Math.max(this.axisLength - projectedValue, 30); + labelLength = Math.max(_this.axisLength - projectedValue, 30); } - // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) + // Skip grid lines and labels where interpolated label values are falsey (except for 0) if (isFalseyButZero(labelValues[index]) && labelValues[index] !== '') { return; } // Transform to global coordinates using the chartRect // We also need to set the label offset for the createLabel function - if (this.units.pos === 'x') { - projectedValue = this.chartRect.x1 + projectedValue; + if (_this.units.pos === 'x') { + projectedValue = _this.chartRect.x1 + projectedValue; labelOffset.x = chartOptions.axisX.labelOffset.x; // If the labels should be positioned in start position (top side for vertical axis) we need to set a // different offset as for positioned with end (bottom) if (chartOptions.axisX.position === 'start') { - labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + labelOffset.y = _this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); } else { - labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); + labelOffset.y = _this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); } } else { - projectedValue = this.chartRect.y1 - projectedValue; + projectedValue = _this.chartRect.y1 - projectedValue; labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0); // If the labels should be positioned in start position (left side for horizontal axis) we need to set a // different offset as for positioned with end (right side) if (chartOptions.axisY.position === 'start') { - labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10; + labelOffset.x = useForeignObject ? _this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : _this.chartRect.x1 - 10; } else { - labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; + labelOffset.x = _this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; } } if (axisOptions.showGrid) { - createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [chartOptions.classNames.grid, chartOptions.classNames[this.units.dir]], eventEmitter); + createGrid(projectedValue, index, _this, _this.gridOffset, _this.chartRect[_this.counterUnits.len](), gridGroup, [chartOptions.classNames.grid, chartOptions.classNames[_this.units.dir]], eventEmitter); } if (axisOptions.showLabel) { - createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [chartOptions.classNames.label, chartOptions.classNames[this.units.dir], axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']], useForeignObject, eventEmitter); + createLabel(projectedValue, labelLength, index, labelValues, _this, axisOptions.offset, labelOffset, labelGroup, [chartOptions.classNames.label, chartOptions.classNames[_this.units.dir], axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames.end], useForeignObject, eventEmitter); } - }.bind(this)); + }); } }]); @@ -2225,8 +2255,8 @@ var FixedScaleAxis = function (_Axis) { var highLow = options.highLow || getHighLow(data, options, axisUnit.pos); _this.divisor = options.divisor || 1; _this.ticks = options.ticks || times(_this.divisor).map(function (value, index) { - return highLow.low + (highLow.high - highLow.low) / this.divisor * index; - }.bind(_this)); + return highLow.low + (highLow.high - highLow.low) / _this.divisor * index; + }); _this.ticks.sort(function (a, b) { return a - b; }); @@ -2506,13 +2536,15 @@ var SvgPath = function () { }, { key: 'parse', value: function parse(path) { + var _pathElements; + // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] - var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2').replace(/([0-9])([A-Za-z])/g, '$1 $2').split(/[\s,]+/).reduce(function (result, element) { - if (element.match(/[A-Za-z]/)) { + var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2').replace(/([0-9])([A-Za-z])/g, '$1 $2').split(/[\s,]+/).reduce(function (result, pathElement) { + if (pathElement.match(/[A-Za-z]/)) { result.push([]); } - result[result.length - 1].push(element); + result[result.length - 1].push(pathElement); return result; }, []); @@ -2524,8 +2556,8 @@ var SvgPath = function () { // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters // For example {command: 'M', x: '10', y: '10'} var elements = chunks.map(function (chunk) { - var command = chunk.shift(), - description = elementDescriptions[command.toLowerCase()]; + var command = chunk.shift(); + var description = elementDescriptions[command.toLowerCase()]; return extend({ command: command @@ -2536,9 +2568,7 @@ var SvgPath = function () { }); // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position - var spliceArgs = [this.pos, 0]; - Array.prototype.push.apply(spliceArgs, elements); - Array.prototype.splice.apply(this.pathElements, spliceArgs); + (_pathElements = this.pathElements).splice.apply(_pathElements, [this.pos, 0].concat(_toConsumableArray(elements))); // Increase the internal position by the element count this.pos += elements.length; @@ -2555,15 +2585,17 @@ var SvgPath = function () { }, { key: 'stringify', value: function stringify() { + var _this = this; + var accuracyMultiplier = Math.pow(10, this.options.accuracy); return this.pathElements.reduce(function (path, pathElement) { var params = elementDescriptions[pathElement.command.toLowerCase()].map(function (paramName) { - return this.options.accuracy ? Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier : pathElement[paramName]; - }.bind(this)); + return _this.options.accuracy ? Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier : pathElement[paramName]; + }); return path + pathElement.command + params.join(','); - }.bind(this), '') + (this.close ? 'Z' : ''); + }, '') + (this.close ? 'Z' : ''); } /** @@ -2579,7 +2611,7 @@ var SvgPath = function () { key: 'scale', value: function scale(x, y) { forEachParam(this.pathElements, function (pathElement, paramName) { - pathElement[paramName] *= paramName[0] === 'x' ? x : y; + return pathElement[paramName] *= paramName[0] === 'x' ? x : y; }); return this; } @@ -2597,7 +2629,7 @@ var SvgPath = function () { key: 'translate', value: function translate(x, y) { forEachParam(this.pathElements, function (pathElement, paramName) { - pathElement[paramName] += paramName[0] === 'x' ? x : y; + return pathElement[paramName] += paramName[0] === 'x' ? x : y; }); return this; } @@ -2638,13 +2670,13 @@ var SvgPath = function () { }, { key: 'clone', value: function clone(close) { - var c = new SvgPath(close || this.close); - c.pos = this.pos; - c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { + var clone = new SvgPath(close || this.close); + clone.pos = this.pos; + clone.pathElements = this.pathElements.slice().map(function (pathElement) { return extend({}, pathElement); }); - c.options = extend({}, this.options); - return c; + clone.options = extend({}, this.options); + return clone; } /** @@ -2696,8 +2728,10 @@ function none(options) { var defaultOptions = { fillHoles: false }; + options = extend({}, defaultOptions, options); - return function none(pathCoordinates, valueData) { + + return function noneInterpolation(pathCoordinates, valueData) { var path = new SvgPath(); var hole = true; @@ -2752,13 +2786,16 @@ function simple(options) { divisor: 2, fillHoles: false }; + options = extend({}, defaultOptions, options); var d = 1 / Math.max(1, options.divisor); - return function simple(pathCoordinates, valueData) { + return function simpleInterpolation(pathCoordinates, valueData) { var path = new SvgPath(); - var prevX, prevY, prevData; + var prevX = void 0; + var prevY = void 0; + var prevData = void 0; for (var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; @@ -2778,7 +2815,7 @@ function simple(options) { prevY = currY; prevData = currData; } else if (!options.fillHoles) { - prevX = currX = prevData = undefined; + prevX = prevY = prevData = undefined; } } @@ -2814,10 +2851,12 @@ function step(options) { options = extend({}, defaultOptions, options); - return function step(pathCoordinates, valueData) { + return function stepInterpolation(pathCoordinates, valueData) { var path = new SvgPath(); - var prevX, prevY, prevData; + var prevX = void 0; + var prevY = void 0; + var prevData = void 0; for (var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; @@ -2882,10 +2921,10 @@ function cardinal(options) { options = extend({}, defaultOptions, options); - var t = Math.min(1, Math.max(0, options.tension)), - c = 1 - t; + var t = Math.min(1, Math.max(0, options.tension)); + var c = 1 - t; - return function cardinal(pathCoordinates, valueData) { + return function cardinalInterpolation(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts var segments = splitIntoSegments(pathCoordinates, valueData, { @@ -2898,13 +2937,11 @@ function cardinal(options) { } else if (segments.length > 1) { // If the split resulted in more that one segment we need to interpolate each segment individually and join them // afterwards together into a single path. - var paths = []; // For each segment we will recurse the cardinal function - segments.forEach(function (segment) { - paths.push(cardinal(segment.pathCoordinates, segment.valueData)); - }); // Join the segment path data into a single path and return - return SvgPath.join(paths); + return SvgPath.join(segments.map(function (segment) { + return cardinalInterpolation(segment.pathCoordinates, segment.valueData); + })); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first // segment @@ -2916,11 +2953,12 @@ function cardinal(options) { return none()(pathCoordinates, valueData); } - var path = new SvgPath().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), - z; + var path = new SvgPath().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]); + var z = void 0; for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { var p = [{ x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1] }, { x: +pathCoordinates[i], y: +pathCoordinates[i + 1] }, { x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3] }, { x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5] }]; + if (z) { if (!i) { p[0] = { x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1] }; @@ -2976,7 +3014,7 @@ function monotoneCubic(options) { options = extend({}, defaultOptions, options); - return function monotoneCubic(pathCoordinates, valueData) { + return function monotoneCubicInterpolation(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts var segments = splitIntoSegments(pathCoordinates, valueData, { @@ -2990,13 +3028,11 @@ function monotoneCubic(options) { } else if (segments.length > 1) { // If the split resulted in more that one segment we need to interpolate each segment individually and join them // afterwards together into a single path. - var paths = []; // For each segment we will recurse the monotoneCubic fn function - segments.forEach(function (segment) { - paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData)); - }); // Join the segment path data into a single path and return - return SvgPath.join(paths); + return SvgPath.join(segments.map(function (segment) { + return monotoneCubicInterpolation(segment.pathCoordinates, segment.valueData); + })); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first // segment @@ -3008,61 +3044,55 @@ function monotoneCubic(options) { return none()(pathCoordinates, valueData); } - var xs = [], - ys = [], - i, - n = pathCoordinates.length / 2, - ms = [], - ds = [], - dys = [], - dxs = [], - path; + var xs = []; + var ys = []; + var n = pathCoordinates.length / 2; + var ms = []; + var ds = []; + var dys = []; + var dxs = []; // Populate x and y coordinates into separate arrays, for readability - - for (i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { xs[i] = pathCoordinates[i * 2]; ys[i] = pathCoordinates[i * 2 + 1]; } // Calculate deltas and derivative - - for (i = 0; i < n - 1; i++) { - dys[i] = ys[i + 1] - ys[i]; - dxs[i] = xs[i + 1] - xs[i]; - ds[i] = dys[i] / dxs[i]; + for (var _i = 0; _i < n - 1; _i++) { + dys[_i] = ys[_i + 1] - ys[_i]; + dxs[_i] = xs[_i + 1] - xs[_i]; + ds[_i] = dys[_i] / dxs[_i]; } // Determine desired slope (m) at each point using Fritsch-Carlson method // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation - ms[0] = ds[0]; ms[n - 1] = ds[n - 2]; - for (i = 1; i < n - 1; i++) { - if (ds[i] === 0 || ds[i - 1] === 0 || ds[i - 1] > 0 !== ds[i] > 0) { - ms[i] = 0; + for (var _i2 = 1; _i2 < n - 1; _i2++) { + if (ds[_i2] === 0 || ds[_i2 - 1] === 0 || ds[_i2 - 1] > 0 !== ds[_i2] > 0) { + ms[_i2] = 0; } else { - ms[i] = 3 * (dxs[i - 1] + dxs[i]) / ((2 * dxs[i] + dxs[i - 1]) / ds[i - 1] + (dxs[i] + 2 * dxs[i - 1]) / ds[i]); + ms[_i2] = 3 * (dxs[_i2 - 1] + dxs[_i2]) / ((2 * dxs[_i2] + dxs[_i2 - 1]) / ds[_i2 - 1] + (dxs[_i2] + 2 * dxs[_i2 - 1]) / ds[_i2]); - if (!isFinite(ms[i])) { - ms[i] = 0; + if (!isFinite(ms[_i2])) { + ms[_i2] = 0; } } } // Now build a path from the slopes + var path = new SvgPath().move(xs[0], ys[0], false, valueData[0]); - path = new SvgPath().move(xs[0], ys[0], false, valueData[0]); - - for (i = 0; i < n - 1; i++) { + for (var _i3 = 0; _i3 < n - 1; _i3++) { path.curve( // First control point - xs[i] + dxs[i] / 3, ys[i] + ms[i] * dxs[i] / 3, + xs[_i3] + dxs[_i3] / 3, ys[_i3] + ms[_i3] * dxs[_i3] / 3, // Second control point - xs[i + 1] - dxs[i] / 3, ys[i + 1] - ms[i + 1] * dxs[i] / 3, + xs[_i3 + 1] - dxs[_i3] / 3, ys[_i3 + 1] - ms[_i3 + 1] * dxs[_i3] / 3, // End point - xs[i + 1], ys[i + 1], false, valueData[i + 1]); + xs[_i3 + 1], ys[_i3 + 1], false, valueData[_i3 + 1]); } return path; @@ -3279,6 +3309,8 @@ var LineChart = function (_BaseChart) { _createClass(LineChart, [{ key: 'createChart', value: function createChart(options) { + var _this2 = this; + var data = normalizeData(this.data, options.reverseData, true); // Create new svg object @@ -3289,7 +3321,8 @@ var LineChart = function (_BaseChart) { var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); var chartRect = createChartRect(this.svg, options, defaultOptions.padding); - var axisX, axisY; + var axisX = void 0; + var axisY = void 0; if (options.axisX.type === undefined) { axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { @@ -3329,8 +3362,8 @@ var LineChart = function (_BaseChart) { // Use series class from series data or if not set generate one seriesElement.addClass([options.classNames.series, series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)].join(' ')); - var pathCoordinates = [], - pathData = []; + var pathCoordinates = []; + var pathData = []; data.normalized.series[seriesIndex].forEach(function (value, valueIndex) { var p = { @@ -3343,7 +3376,7 @@ var LineChart = function (_BaseChart) { valueIndex: valueIndex, meta: getMetaData(series, valueIndex) }); - }.bind(this)); + }); var seriesOptions = { lineSmooth: getSeriesOption(series, options, 'lineSmooth'), @@ -3353,7 +3386,13 @@ var LineChart = function (_BaseChart) { areaBase: getSeriesOption(series, options, 'areaBase') }; - var smoothing = typeof seriesOptions.lineSmooth === 'function' ? seriesOptions.lineSmooth : seriesOptions.lineSmooth ? monotoneCubic() : none(); + var smoothing = void 0; + if (typeof seriesOptions.lineSmooth === 'function') { + smoothing = seriesOptions.lineSmooth; + } else { + smoothing = seriesOptions.lineSmooth ? monotoneCubic() : none(); + } + // Interpolating path where pathData will be used to annotate each path element so we can trace back the original // index, value and meta data var path = smoothing(pathCoordinates, pathData); @@ -3374,7 +3413,7 @@ var LineChart = function (_BaseChart) { 'ct:meta': serialize(pathElement.data.meta) }); - this.eventEmitter.emit('draw', { + _this2.eventEmitter.emit('draw', { type: 'point', value: pathElement.data.value, index: pathElement.data.valueIndex, @@ -3388,7 +3427,7 @@ var LineChart = function (_BaseChart) { x: pathElement.x, y: pathElement.y }); - }.bind(this)); + }); } if (seriesOptions.showLine) { @@ -3396,11 +3435,12 @@ var LineChart = function (_BaseChart) { d: path.stringify() }, options.classNames.line, true); - this.eventEmitter.emit('draw', { + _this2.eventEmitter.emit('draw', { type: 'line', values: data.normalized.series[seriesIndex], path: path.clone(), chartRect: chartRect, + // TODO: Remove redundant index: seriesIndex, series: series, seriesIndex: seriesIndex, @@ -3414,53 +3454,58 @@ var LineChart = function (_BaseChart) { // Area currently only works with axes that support a range! if (seriesOptions.showArea && axisY.range) { - // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that - // the area is not drawn outside the chart area. - var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); + (function () { + // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that + // the area is not drawn outside the chart area. + var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); - // We project the areaBase value into screen coordinates - var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); + // We project the areaBase value into screen coordinates + var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); - // In order to form the area we'll first split the path by move commands so we can chunk it up into segments - path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { + // In order to form the area we'll first split the path by move commands so we can chunk it up into segments + path.splitByCommand('M') // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area - return pathSegment.pathElements.length > 1; - }).map(function convertToArea(solidPathSegments) { - // Receiving the filtered solid path segments we can now convert those segments into fill areas - var firstElement = solidPathSegments.pathElements[0]; - var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; - - // Cloning the solid path segment with closing option and removing the first move command from the clone - // We then insert a new move that should start at the area base and draw a straight line up or down - // at the end of the path we add an additional straight line to the projected area base value - // As the closing option is set our path will be automatically closed - return solidPathSegments.clone(true).position(0).remove(1).move(firstElement.x, areaBaseProjected).line(firstElement.x, firstElement.y).position(solidPathSegments.pathElements.length + 1).line(lastElement.x, areaBaseProjected); - }).forEach(function createArea(areaPath) { - // For each of our newly created area paths, we'll now create path elements by stringifying our path objects - // and adding the created DOM elements to the correct series group - var area = seriesElement.elem('path', { - d: areaPath.stringify() - }, options.classNames.area, true); - - // Emit an event for each area that was drawn - this.eventEmitter.emit('draw', { - type: 'area', - values: data.normalized.series[seriesIndex], - path: areaPath.clone(), - series: series, - seriesIndex: seriesIndex, - axisX: axisX, - axisY: axisY, - chartRect: chartRect, - index: seriesIndex, - group: seriesElement, - element: area + .filter(function (pathSegment) { + return pathSegment.pathElements.length > 1; + }).map(function (solidPathSegments) { + // Receiving the filtered solid path segments we can now convert those segments into fill areas + var firstElement = solidPathSegments.pathElements[0]; + var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; + + // Cloning the solid path segment with closing option and removing the first move command from the clone + // We then insert a new move that should start at the area base and draw a straight line up or down + // at the end of the path we add an additional straight line to the projected area base value + // As the closing option is set our path will be automatically closed + return solidPathSegments.clone(true).position(0).remove(1).move(firstElement.x, areaBaseProjected).line(firstElement.x, firstElement.y).position(solidPathSegments.pathElements.length + 1).line(lastElement.x, areaBaseProjected); + }).forEach(function (areaPath) { + // For each of our newly created area paths, we'll now create path elements by stringifying our path objects + // and adding the created DOM elements to the correct series group + var area = seriesElement.elem('path', { + d: areaPath.stringify() + }, options.classNames.area, true); + + // Emit an event for each area that was drawn + _this2.eventEmitter.emit('draw', { + type: 'area', + values: data.normalized.series[seriesIndex], + path: areaPath.clone(), + series: series, + seriesIndex: seriesIndex, + axisX: axisX, + axisY: axisY, + chartRect: chartRect, + // TODO: Remove redundant + index: seriesIndex, + group: seriesElement, + element: area + }); }); - }.bind(this)); + })(); } - }.bind(this)); + }); this.eventEmitter.emit('created', { + // TODO: Remove redundant bounds: axisY.bounds, chartRect: chartRect, axisX: axisX, @@ -3629,8 +3674,11 @@ var BarChart = function (_BaseChart) { _createClass(BarChart, [{ key: 'createChart', value: function createChart(options) { - var data; - var highLow; + var _arguments = arguments, + _this2 = this; + + var data = void 0; + var highLow = void 0; if (options.distributeSeries) { data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); @@ -3650,10 +3698,9 @@ var BarChart = function (_BaseChart) { var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); if (options.stackBars && data.normalized.series.length !== 0) { - // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = serialMap(data.normalized.series, function serialSums() { - return Array.prototype.slice.call(arguments).map(function (value) { + var serialSums = serialMap(data.normalized.series, function () { + return Array.from(_arguments).map(function (value) { return value; }).reduce(function (prev, curr) { return { @@ -3665,7 +3712,6 @@ var BarChart = function (_BaseChart) { highLow = getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y'); } else { - highLow = getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y'); } @@ -3674,8 +3720,11 @@ var BarChart = function (_BaseChart) { highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); var chartRect = createChartRect(this.svg, options, defaultOptions$2.padding); - - var valueAxis, labelAxisTicks, labelAxis, axisX, axisY; + var valueAxis = void 0; + var labelAxisTicks = void 0; + var labelAxis = void 0; + var axisX = void 0; + var axisY = void 0; // We need to set step count based on some options combinations if (options.distributeSeries && options.stackBars) { @@ -3725,7 +3774,7 @@ var BarChart = function (_BaseChart) { referenceValue: 0 })); } else { - valueAxis = axisY = new options.axisY.type(axisUnits.units.y, data.normalized.series, chartRect, extend({}, options.axisY, { + valueAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); @@ -3749,9 +3798,7 @@ var BarChart = function (_BaseChart) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. var biPol = seriesIndex - (data.raw.series.length - 1) / 2; // Half of the period width between vertical grid lines used to position bars - var periodHalfLength; - // Current series SVG element - var seriesElement; + var periodHalfLength = void 0; // We need to set periodHalfLength based on some options combinations if (options.distributeSeries && !options.stackBars) { @@ -3768,7 +3815,7 @@ var BarChart = function (_BaseChart) { } // Adding the series group to the series element - seriesElement = seriesGroup.elem('g'); + var seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ @@ -3780,8 +3827,7 @@ var BarChart = function (_BaseChart) { seriesElement.addClass([options.classNames.series, series.className || options.classNames.series + '-' + alphaNumerate(seriesIndex)].join(' ')); data.normalized.series[seriesIndex].forEach(function (value, valueIndex) { - var projected, bar, previousStack, labelAxisValueIndex; - + var labelAxisValueIndex = void 0; // We need to set labelAxisValueIndex based on some options combinations if (options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection @@ -3796,6 +3842,7 @@ var BarChart = function (_BaseChart) { labelAxisValueIndex = valueIndex; } + var projected = void 0; // We need to transform coordinates differently based on the chart layout if (options.horizontalBars) { projected = { @@ -3823,7 +3870,7 @@ var BarChart = function (_BaseChart) { } // Enter value in stacked bar values used to remember previous screen value for stacking up bars - previousStack = stackedBarValues[valueIndex] || zeroPoint; + var previousStack = stackedBarValues[valueIndex] || zeroPoint; stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); // Skip if value is undefined @@ -3858,12 +3905,12 @@ var BarChart = function (_BaseChart) { var metaData = getMetaData(series, valueIndex); // Create bar element - bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ + var bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'ct:value': [value.x, value.y].filter(isNumeric).join(','), 'ct:meta': serialize(metaData) }); - this.eventEmitter.emit('draw', extend({ + _this2.eventEmitter.emit('draw', extend({ type: 'bar', value: value, index: valueIndex, @@ -3876,8 +3923,8 @@ var BarChart = function (_BaseChart) { group: seriesElement, element: bar }, positions)); - }.bind(this)); - }.bind(this)); + }); + }); this.eventEmitter.emit('created', { bounds: valueAxis.bounds, @@ -4046,25 +4093,22 @@ var PieChart = function (_BaseChart) { _createClass(PieChart, [{ key: 'createChart', value: function createChart(options) { + var _this2 = this; + var data = normalizeData(this.data); - var seriesGroups = [], - labelsGroup, - chartRect, - radius, - labelRadius, - totalDataSum, - startAngle = options.startAngle; + var seriesGroups = []; + var labelsGroup = void 0; + var labelRadius = void 0; + var startAngle = options.startAngle; // Create SVG.js draw this.svg = createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie); // Calculate charting rect - chartRect = createChartRect(this.svg, options, defaultOptions$3.padding); + var chartRect = createChartRect(this.svg, options, defaultOptions$3.padding); // Get biggest circle radius possible within chartRect - radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); + var radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); // Calculate total of all series to get reference value or use total reference from optional options - totalDataSum = options.total || data.normalized.series.reduce(function (previousValue, currentValue) { - return previousValue + currentValue; - }, 0); + var totalDataSum = options.total || data.normalized.series.reduce(sum, 0); var donutWidth = quantity(options.donutWidth); if (donutWidth.unit === '%') { @@ -4104,9 +4148,9 @@ var PieChart = function (_BaseChart) { // Creating the series groups data.raw.series.forEach(function (series, index) { - seriesGroups[index] = this.svg.elem('g', null, null); - }.bind(this)); - //if we need to show labels we create the label group now + return seriesGroups[index] = _this2.svg.elem('g', null, null); + }); + // if we need to show labels we create the label group now if (options.showLabel) { labelsGroup = this.svg.elem('g', null, null); } @@ -4115,7 +4159,9 @@ var PieChart = function (_BaseChart) { // initialize series groups data.raw.series.forEach(function (series, index) { // If current value is zero and we are ignoring empty values then skip to next value - if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; + if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) { + return; + } // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[index].attr({ @@ -4137,8 +4183,8 @@ var PieChart = function (_BaseChart) { endAngle = overlappigStartAngle + 359.99; } - var start = polarToCartesian(center.x, center.y, radius, overlappigStartAngle), - end = polarToCartesian(center.x, center.y, radius, endAngle); + var start = polarToCartesian(center.x, center.y, radius, overlappigStartAngle); + var end = polarToCartesian(center.x, center.y, radius, endAngle); // 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 SvgPath(!options.donut).move(end.x, end.y).arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y); @@ -4168,7 +4214,7 @@ var PieChart = function (_BaseChart) { } // Fire off draw event - this.eventEmitter.emit('draw', { + _this2.eventEmitter.emit('draw', { type: 'slice', value: data.normalized.series[index], totalDataSum: totalDataSum, @@ -4186,7 +4232,8 @@ var PieChart = function (_BaseChart) { // If we need to show labels we need to add the label for this slice now if (options.showLabel) { - var labelPosition; + var labelPosition = void 0; + if (data.raw.series.length === 1) { // If we have only 1 series, we can position the label in the center of the pie labelPosition = { @@ -4198,7 +4245,7 @@ var PieChart = function (_BaseChart) { labelPosition = polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2); } - var rawValue; + var rawValue = void 0; if (data.normalized.labels && !isFalseyButZero(data.normalized.labels[index])) { rawValue = data.normalized.labels[index]; } else { @@ -4215,7 +4262,7 @@ var PieChart = function (_BaseChart) { }, options.classNames.label).text('' + interpolatedValue); // Fire off draw event - this.eventEmitter.emit('draw', { + _this2.eventEmitter.emit('draw', { type: 'label', index: index, group: labelsGroup, @@ -4230,7 +4277,7 @@ var PieChart = function (_BaseChart) { // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; - }.bind(this)); + }); this.eventEmitter.emit('created', { chartRect: chartRect, @@ -4243,6 +4290,6 @@ var PieChart = function (_BaseChart) { return PieChart; }(BaseChart); -export { interpolation as Interpolation, EventEmitter, extend, optionsProvider, namespaces, precision, escapingMap, version, replaceAll, querySelector$1 as querySelector, safeHasProperty, isNumeric, isFalseyButZero, getNumberOrUndefined, ensureUnit, quantity, alphaNumerate, noop, times, sum, mapMultiply, mapAdd, serialMap, orderOfMagnitude, projectLength, roundWithPrecision, rho, polarToCartesian, serialize, deserialize, normalizeData, getMetaData, isDataHoleValue, reverseData, getDataArray, isMultiValue, getMultiValue, getSeriesOption, splitIntoSegments, getHighLow, getBounds, createSvg, normalizePadding, createChartRect, createGrid, createGridBackground, createLabel, BaseChart, LineChart, BarChart, PieChart, Axis, axisUnits, AutoScaleAxis, FixedScaleAxis, StepAxis, Svg, isSupported, easings, SvgList, SvgPath }; +export { interpolation as Interpolation, EventEmitter, extend, optionsProvider, namespaces, precision, escapingMap, version, replaceAll, querySelector$1 as querySelector, safeHasProperty, isNumeric, isFalseyButZero, getNumberOrUndefined, ensureUnit, quantity, alphaNumerate, noop, times, sum, serialMap, EPSILON, orderOfMagnitude, projectLength, roundWithPrecision, rho, polarToCartesian, serialize, deserialize, normalizeData, getMetaData, isDataHoleValue, reverseData, getDataArray, isMultiValue, getMultiValue, getSeriesOption, splitIntoSegments, getHighLow, getBounds, createSvg, normalizePadding, createChartRect, createGrid, createGridBackground, createLabel, BaseChart, LineChart, BarChart, PieChart, Axis, axisUnits, AutoScaleAxis, FixedScaleAxis, StepAxis, Svg, isSupported, easings, SvgList, SvgPath }; //# sourceMappingURL=chartist.esm.js.map \ No newline at end of file diff --git a/dist/chartist.esm.js.map b/dist/chartist.esm.js.map index b231d866..4bd851fb 100644 --- a/dist/chartist.esm.js.map +++ b/dist/chartist.esm.js.map @@ -1 +1 @@ -{"version":3,"sources":["../package.json!file:/home/gion/Code/chartist/tooling/system-loaders/package.json","../src/core/globals.js","../src/core/lang.js","../src/core/functional.js","../src/core/math.js","../src/core/extend.js","../src/core/data.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/classCallCheck.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/createClass.js","../src/svg/svg-list.js","../src/svg/svg.js","../src/core/creation.js","../src/core/options-provider.js","../src/event/event-emitter.js","../src/charts/base.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/possibleConstructorReturn.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/inherits.js","../src/axes/axis.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/get.js","../src/axes/auto-scale-axis.js","../src/axes/fixed-scale-axis.js","../src/axes/step-axis.js","../src/svg/svg-path.js","../src/interpolation/none.js","../src/interpolation/simple.js","../src/interpolation/step.js","../src/interpolation/cardinal.js","../src/interpolation/monotone-cubic.js","../src/charts/line.js","../src/charts/bar.js","../src/charts/pie.js"],"names":["version","namespaces","precision","escapingMap","replaceAll","str","subStr","newSubStr","replace","RegExp","querySelector","query","Node","document","safeHasProperty","object","property","hasOwnProperty","isNumeric","value","isFinite","isFalseyButZero","getNumberOrUndefined","undefined","ensureUnit","unit","quantity","input","match","exec","alphaNumerate","n","String","fromCharCode","noop","times","length","Array","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","forEach","index","args","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","roundWithPrecision","digits","pow","round","rho","gcd","p","q","f","x","x1","x2","divisor","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","extend","target","i","source","sourceProp","arguments","prop","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","normalizeData","reverse","multi","labelCount","output","normalized","series","getDataArray","every","labels","slice","prototype","push","getMetaData","meta","isDataHoleValue","isNaN","reverseData","recursiveConvert","multiValue","y","isMultiValue","getMultiValue","dimension","getSeriesOption","options","name","seriesOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","segments","hole","fillHoles","increasingX","getHighLow","toUpperCase","highLow","high","Number","MAX_VALUE","low","findHigh","findLow","recursiveHighLow","referenceValue","min","getBounds","scaleMinSpace","onlyInteger","optimizationCounter","newMin","newMax","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","EPSILON","safeIncrement","increment","values","instance","Constructor","TypeError","defineProperties","props","descriptor","enumerable","configurable","writable","defineProperty","protoProps","staticProps","SvgList","nodeList","list","svgElements","Svg","filter","prototypeProperty","indexOf","call","element","attributes","className","parent","insertFirst","Element","_node","createElementNS","svg","attr","ct","addClass","firstChild","insertBefore","appendChild","ns","getAttributeNS","getAttribute","namespacedAttribute","split","setAttributeNS","setAttribute","bind","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","querySelectorAll","content","container","createElement","innerHTML","xmlns","fnObj","elem","t","createTextNode","removeChild","newElement","replaceChild","trim","names","classes","concat","pos","self","join","removedClasses","getBoundingClientRect","height","width","animations","guided","eventEmitter","createAnimateForAttributes","attribute","createAnimate","animationDefinition","attributeProperties","animate","timeout","animationEasing","easing","easings","begin","dur","calcMode","keySplines","keyTimes","fill","from","beginElement","err","to","remove","addEventListener","handleBeginEvent","emit","handleEndEvent","isSupported","feature","implementation","hasFeature","createSvg","filterChartistSvgObjects","removePreviousElement","normalizePadding","padding","fallback","top","right","bottom","left","createChartRect","fallbackPadding","hasAxis","axisX","axisY","yAxisOffset","offset","xAxisOffset","normalizedPadding","chartPadding","chartRect","y1","y2","position","createGrid","axis","group","positionalData","units","counterUnits","gridElement","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","foreignObject","text","optionsProvider","responsiveOptions","baseOptions","currentOptions","mediaQueryListeners","updateCurrentOptions","mediaEvent","previousOptions","mql","window","matchMedia","matches","removeMediaQueryListeners","removeListener","addListener","getCurrentOptions","EventEmitter","handlers","event","handler","splice","starHandler","BaseChart","supportsForeignObject","supportsAnimations","resizeListener","update","__chartist__","detach","initializeTimeoutId","setTimeout","initialize","override","createChart","removeEventListener","clearTimeout","addEventHandler","removeEventHandler","plugins","plugin","ReferenceError","subClass","superClass","create","setPrototypeOf","__proto__","axisUnits","Axis","ticks","rectEnd","rectStart","gridOffset","rectOffset","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","get","receiver","Function","desc","getOwnPropertyDescriptor","getPrototypeOf","getter","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","a","b","stepLength","StepAxis","calc","stretch","elementDescriptions","command","params","pathElements","relative","pathElement","toLowerCase","forEachParam","pathElementIndex","paramName","paramIndex","SvgPath","paths","close","joinedPath","path","j","count","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","transformFnc","transformed","c","cloneElements","none","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","postpone","cardinal","tension","segment","z","iLen","monotoneCubic","xs","ys","ms","ds","dys","dxs","LineChart","chart","seriesGroup","type","fullWidth","createGridAndLabels","showGridBackground","raw","seriesIndex","seriesElement","pathData","valueIndex","smoothing","lineSmooth","showPoint","point","showLine","clone","showArea","areaBase","areaBaseProjected","splitByCommand","onlySolidSegments","pathSegment","convertToArea","solidPathSegments","firstElement","lastElement","createArea","areaPath","area","BarChart","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","biPol","periodHalfLength","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","stackMode","metaData","determineAnchorPosition","center","direction","toTheRight","PieChart","seriesGroups","labelsGroup","labelRadius","totalDataSum","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","start","end","arc","sliceDonut","slicePie","rawValue","interpolatedValue","labelDirection"],"mappings":"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","file":"chartist.esm.js"} \ No newline at end of file +{"version":3,"sources":["../package.json!file:/home/gion/Code/chartist/tooling/system-loaders/package.json","../src/core/globals.js","../src/core/lang.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/toConsumableArray.js","../src/core/functional.js","../src/core/math.js","../src/core/extend.js","../src/core/data.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/classCallCheck.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/createClass.js","../src/svg/svg-list.js","../src/svg/svg.js","../src/core/creation.js","../src/core/options-provider.js","../src/event/event-emitter.js","../src/charts/base.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/possibleConstructorReturn.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/inherits.js","../src/axes/axis.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/get.js","../src/axes/auto-scale-axis.js","../src/axes/fixed-scale-axis.js","../src/axes/step-axis.js","../src/svg/svg-path.js","../src/interpolation/none.js","../src/interpolation/simple.js","../src/interpolation/step.js","../src/interpolation/cardinal.js","../src/interpolation/monotone-cubic.js","../src/charts/line.js","../src/charts/bar.js","../src/charts/pie.js"],"names":["version","namespaces","precision","escapingMap","replaceAll","str","subStr","newSubStr","replace","RegExp","querySelector","query","Node","document","safeHasProperty","object","property","hasOwnProperty","isNumeric","value","isFinite","isFalseyButZero","getNumberOrUndefined","undefined","ensureUnit","unit","quantity","input","match","exec","alphaNumerate","n","String","fromCharCode","arr","Array","isArray","i","arr2","length","from","noop","times","sum","previous","current","serialMap","array","callback","Math","max","map","element","inner","index","EPSILON","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","roundWithPrecision","digits","pow","globalPrecision","round","rho","num","gcd","p","q","f","x","x1","x2","divisor","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","extend","target","sources","source","prop","sourceProp","serialize","data","JSON","stringify","Object","keys","reduce","result","key","deserialize","parse","e","normalizeData","reverse","multi","labelCount","output","normalized","series","getDataArray","every","labels","slice","push","getMetaData","meta","isDataHoleValue","isNaN","reverseData","recursiveConvert","multiValue","y","isMultiValue","getMultiValue","dimension","getSeriesOption","options","name","seriesOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","segments","hole","fillHoles","increasingX","getHighLow","toUpperCase","highLow","high","Number","MAX_VALUE","low","findHigh","findLow","recursiveHighLow","sourceData","referenceValue","min","getBounds","scaleMinSpace","onlyInteger","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","optimizationCounter","Error","safeIncrement","increment","newMin","newMax","values","instance","Constructor","TypeError","defineProperties","props","descriptor","enumerable","configurable","writable","defineProperty","protoProps","staticProps","prototype","SvgList","nodeList","list","svgElements","Svg","filter","prototypeProperty","indexOf","forEach","args","apply","attributes","className","parent","insertFirst","Element","_node","createElementNS","svg","attr","ct","addClass","firstChild","insertBefore","appendChild","ns","getAttributeNS","getAttribute","namespacedAttribute","split","setAttributeNS","setAttribute","bind","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","querySelectorAll","content","container","createElement","innerHTML","xmlns","fnObj","elem","t","createTextNode","removeChild","newElement","replaceChild","trim","names","classes","concat","pos","self","join","removedClasses","getBoundingClientRect","height","width","animations","guided","eventEmitter","attribute","createAnimate","animationDefinition","createGuided","attributeProperties","animationEasing","timeout","easing","easings","begin","dur","calcMode","keySplines","keyTimes","fill","animate","beginElement","err","to","remove","addEventListener","emit","isSupported","feature","implementation","hasFeature","createSvg","normalizePadding","padding","fallback","top","right","bottom","left","createChartRect","fallbackPadding","hasAxis","axisX","axisY","yAxisOffset","offset","xAxisOffset","normalizedPadding","chartPadding","chartRect","y1","y2","position","createGrid","axis","group","positionalData","units","counterUnits","gridElement","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","stepLength","stepCounterLength","foreignObject","text","optionsProvider","responsiveOptions","baseOptions","currentOptions","mediaQueryListeners","updateCurrentOptions","mediaEvent","previousOptions","responsiveOption","mql","window","matchMedia","matches","removeMediaQueryListeners","removeListener","addListener","EventEmitter","handlers","event","handler","splice","starHandler","BaseChart","supportsForeignObject","supportsAnimations","resizeListener","update","__chartist__","detach","initializeTimeoutId","setTimeout","initialize","override","createChart","getCurrentOptions","removeEventListener","clearTimeout","addEventHandler","removeEventHandler","plugins","plugin","call","ReferenceError","subClass","superClass","create","setPrototypeOf","__proto__","axisUnits","Axis","ticks","rectEnd","rectStart","gridOffset","rectOffset","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","end","get","receiver","Function","desc","getOwnPropertyDescriptor","getPrototypeOf","getter","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","a","b","StepAxis","calc","stretch","elementDescriptions","command","params","pathElements","relative","pathElement","toLowerCase","forEachParam","cb","pathElementIndex","paramName","paramIndex","SvgPath","paths","close","joinedPath","path","j","count","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","accuracyMultiplier","accuracy","transformFnc","transformed","clone","none","noneInterpolation","currX","currY","currData","move","line","simple","d","simpleInterpolation","prevX","prevY","prevData","curve","stepInterpolation","postpone","cardinal","tension","c","cardinalInterpolation","segment","z","iLen","monotoneCubic","monotoneCubicInterpolation","xs","ys","ms","ds","dys","dxs","LineChart","chart","seriesGroup","type","fullWidth","createGridAndLabels","showGridBackground","raw","seriesIndex","seriesElement","pathData","valueIndex","smoothing","lineSmooth","showPoint","point","showLine","showArea","areaBase","areaBaseProjected","splitByCommand","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","BarChart","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","biPol","periodHalfLength","labelAxisValueIndex","projected","seriesBarDistance","previousStack","positions","stackMode","metaData","bar","determineAnchorPosition","center","direction","toTheRight","PieChart","seriesGroups","labelsGroup","labelRadius","startAngle","donut","chartDonut","chartPie","totalDataSum","total","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","start","arc","sliceDonut","slicePie","rawValue","interpolatedValue","labelDirection"],"mappings":"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","file":"chartist.esm.js"} \ No newline at end of file diff --git a/dist/chartist.umd.js b/dist/chartist.umd.js index ea9f9ab1..66bdda63 100644 --- a/dist/chartist.umd.js +++ b/dist/chartist.umd.js @@ -1,9 +1,9 @@ /* Chartist.js 1.0.0 * Copyright © 2016 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 + * https://raw.githubusercontent.com/chartist-js/chartist/master/LICENSE-WTFPL + * https://raw.githubusercontent.com/chartist-js/chartist/master/LICENSE-MIT */ -!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?b(exports):"function"==typeof define&&define.amd?define(["exports"],b):b(a.Chartist=a.Chartist||{})}(this,function(a){"use strict";function b(a,b,c){return a.replace(new RegExp(b,"g"),c)}function c(a){return a instanceof Node?a:document.querySelector(a)}function d(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)}function e(a){return null!==a&&isFinite(a)}function f(a){return!a&&0!==a}function g(a){return e(a)?+a:void 0}function h(a,b){return"number"==typeof a&&(a+=b),a}function i(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}}function j(a){return String.fromCharCode(97+a%26)}function k(a){return a}function l(a){return Array.apply(null,new Array(a))}function m(a,b){return a+(b?b:0)}function n(a){return function(b){return b*a}}function o(a){return function(b){return b+a}}function p(a,b){var c=[],d=Math.max.apply(null,a.map(function(a){return a.length}));return l(d).forEach(function(d,e){var f=a.map(function(a){return a[e]});c[e]=b.apply(null,f)}),c}function q(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)}function r(a,b,c){return b/c.range*a}function s(a,b){var c=Math.pow(10,b||c);return Math.round(a*c)/c}function t(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}function u(a,b,c,d){var e=(d-90)*Math.PI/180;return{x:a+c*Math.cos(e),y:b+c*Math.sin(e)}}function v(a){var b,c,d;for(a=a||{},b=1;b=2&&a[g]<=a[g-2]&&(f=!0),f&&(e.push({pathCoordinates:[],valueData:[]}),f=!1),e[e.length-1].pathCoordinates.push(a[g],a[g+1]),e[e.length-1].valueData.push(b[g/2]));return e}function H(a,b,c){function d(a){if(void 0!==a)if(a instanceof Array)for(var b=0;be.high&&(e.high=h),g&&h0?e.low=0:(e.high=1,e.low=0)),e}function I(a,b,c,d){function e(a,b){return a===(a+=b)&&(a*=1+(b>0?n:-n)),a}var f,g,h,i=0,j={high:b.high,low:b.low};j.valueRange=j.high-j.low,j.oom=q(j.valueRange),j.step=Math.pow(10,j.oom),j.min=Math.floor(j.low/j.step)*j.step,j.max=Math.ceil(j.high/j.step)*j.step,j.range=j.max-j.min,j.numberOfSteps=Math.round(j.range/j.step);var k=r(a,j.step,j),l=k=c)j.step=1;else if(d&&m=c)j.step=m;else for(;;){if(l&&r(a,j.step,j)<=c)j.step*=2;else{if(l||!(r(a,j.step/2,j)>=c))break;if(j.step/=2,d&&j.step%1!==0){j.step*=2;break}}if(i++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var n=2.221e-16;for(j.step=Math.max(j.step,n),g=j.min,h=j.max;g+j.step<=j.low;)g=e(g,j.step);for(;h-j.step>=j.high;)h=e(h,-j.step);j.min=g,j.max=h,j.range=j.max-j.min;var o=[];for(f=j.min;f<=j.max;f=e(f,j.step)){var p=s(f);p!==o[o.length-1]&&o.push(f)}return j.values=o,j}function J(a){return document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#"+a,"1.1")}function K(a,b,c,d){var e;return b=b||"100%",c=c||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS($.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),e=new ea("svg").attr({width:b,height:c}).addClass(d).attr({style:"width: "+b+"; height: "+c+";"}),a.appendChild(e._node),e}function L(a,b){return b=b||0,"number"==typeof a?{top:a,right:a,bottom:a,left:a}:{top:"number"==typeof a.top?a.top:b,right:"number"==typeof a.right?a.right:b,bottom:"number"==typeof a.bottom?a.bottom:b,left:"number"==typeof a.left?a.left:b}}function M(a,b,c){var d=!(!b.axisX&&!b.axisY),e=d?b.axisY.offset:0,f=d?b.axisX.offset:0,g=a.width()||i(b.width).value||0,h=a.height()||i(b.height).value||0,j=L(b.chartPadding,c);g=Math.max(g,e+j.left+j.right),h=Math.max(h,f+j.top+j.bottom);var k={padding:j,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return d?("start"===b.axisX.position?(k.y2=j.top+f,k.y1=Math.max(h-j.bottom,k.y2+1)):(k.y2=j.top,k.y1=Math.max(h-j.bottom-f,k.y2+1)),"start"===b.axisY.position?(k.x1=j.left+e,k.x2=Math.max(g-j.right,k.x1+1)):(k.x1=j.left,k.x2=Math.max(g-j.right-e,k.x1+1))):(k.x1=j.left,k.x2=Math.max(g-j.right,k.x1+1),k.y2=j.top,k.y1=Math.max(h-j.bottom,k.y2+1)),k}function N(a,b,c,d,e,f,g,h){var i={};i[c.units.pos+"1"]=a,i[c.units.pos+"2"]=a,i[c.counterUnits.pos+"1"]=d,i[c.counterUnits.pos+"2"]=d+e;var j=f.elem("line",i,g.join(" "));h.emit("draw",v({type:"grid",axis:c,index:b,group:f,element:j},i))}function O(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})}function P(a,b,c,d,e,f,g,h,i,j,k){var l,m={};if(m[e.units.pos]=a+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=b,m[e.counterUnits.len]=Math.max(0,f-10),j){var n=''+d[c]+"";l=h.foreignObject(n,v({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[c]);k.emit("draw",v({type:"label",axis:e,index:c,group:h,element:l,text:d[c]},m))}function Q(a,b,c){function d(a){var d=f;if(f=v({},h),b)for(g=0;g1){var h=[];return g.forEach(function(a){h.push(b(a.pathCoordinates,a.valueData))}),sa.join(h)}if(e=g[0].pathCoordinates,f=g[0].valueData,e.length<=4)return T()(e,f);for(var i,j=(new sa).move(e[0],e[1],!1,f[0]),k=0,l=e.length;l-2*!i>k;k+=2){var m=[{x:+e[k-2],y:+e[k-1]},{x:+e[k],y:+e[k+1]},{x:+e[k+2],y:+e[k+3]},{x:+e[k+4],y:+e[k+5]}];i?k?l-4===k?m[3]={x:+e[0],y:+e[1]}:l-2===k&&(m[2]={x:+e[0],y:+e[1]},m[3]={x:+e[2],y:+e[3]}):m[0]={x:+e[l-2],y:+e[l-1]}:l-4===k?m[3]=m[2]:k||(m[0]={x:+e[k],y:+e[k+1]}),j.curve(c*(-m[0].x+6*m[1].x+m[2].x)/6+d*m[2].x,c*(-m[0].y+6*m[1].y+m[2].y)/6+d*m[2].y,c*(m[1].x+6*m[2].x-m[3].x)/6+d*m[2].x,c*(m[1].y+6*m[2].y-m[3].y)/6+d*m[2].y,m[2].x,m[2].y,!1,f[(k+2)/2])}return j}return T()([])}}function X(a){var b={fillHoles:!1};return a=v({},b,a),function b(c,d){var e=G(c,d,{fillHoles:a.fillHoles,increasingX:!0});if(e.length){if(e.length>1){var f=[];return e.forEach(function(a){f.push(b(a.pathCoordinates,a.valueData))}),sa.join(f)}if(c=e[0].pathCoordinates,d=e[0].valueData,c.length<=4)return T()(c,d);var g,h,i=[],j=[],k=c.length/2,l=[],m=[],n=[],o=[];for(g=0;g0!=m[g]>0?l[g]=0:(l[g]=3*(o[g-1]+o[g])/((2*o[g]+o[g-1])/m[g-1]+(o[g]+2*o[g-1])/m[g]),isFinite(l[g])||(l[g]=0));for(h=(new sa).move(i[0],j[0],!1,d[0]),g=0;ga.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}var Z="1.0.0",$={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"},_=8,aa={"&":"&","<":"<",">":">",'"':""","'":"'"},ba=function(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")},ca=function(){function a(a,b){for(var c=0;c1}).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,s).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,s)}).forEach(function(e){var g=k.elem("path",{d:e.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:b.normalized.series[h],path:e.clone(),series:f,seriesIndex:h,axisX:c,axisY:d,chartRect:i,index:h,group:k,element:g})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:d.bounds,chartRect:i,axisX:c,axisY:d,svg:this.svg,options:a})}}]),b}(ha),wa={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:k,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:k,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"}},xa=function(a){function b(a,c,d,e){return ba(this,b),ia(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,a,c,wa,v({},wa,d),e))}return ja(b,a),ca(b,[{key:"createChart",value:function(a){var b,c;a.distributeSeries?(b=y(this.data,a.reverseData,a.horizontalBars?"x":"y"),b.normalized.series=b.normalized.series.map(function(a){return[a]})):b=y(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=K(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var d=this.svg.elem("g").addClass(a.classNames.gridGroup),f=this.svg.elem("g"),g=this.svg.elem("g").addClass(a.classNames.labelGroup);if(a.stackBars&&0!==b.normalized.series.length){var h=p(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})});c=H([h],a,a.horizontalBars?"x":"y")}else c=H(b.normalized.series,a,a.horizontalBars?"x":"y");c.high=+a.high||(0===a.high?0:c.high),c.low=+a.low||(0===a.low?0:c.low);var i,k,l,m,n,o=M(this.svg,a,wa.padding);k=a.distributeSeries&&a.stackBars?b.normalized.labels.slice(0,1):b.normalized.labels,a.horizontalBars?(i=m=void 0===a.axisX.type?new na(ka.x,b.normalized.series,o,v({},a.axisX,{ -highLow:c,referenceValue:0})):new a.axisX.type(ka.x,b.normalized.series,o,v({},a.axisX,{highLow:c,referenceValue:0})),l=n=void 0===a.axisY.type?new pa(ka.y,b.normalized.series,o,{ticks:k}):new a.axisY.type(ka.y,b.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new pa(ka.x,b.normalized.series,o,{ticks:k}):new a.axisX.type(ka.x,b.normalized.series,o,a.axisX),i=n=void 0===a.axisY.type?new na(ka.y,b.normalized.series,o,v({},a.axisY,{highLow:c,referenceValue:0})):new a.axisY.type(ka.units.y,b.normalized.series,o,v({},a.axisY,{highLow:c,referenceValue:0})));var q=a.horizontalBars?o.x1+i.projectValue(0):o.y1-i.projectValue(0),r=[];l.createGridAndLabels(d,g,this.supportsForeignObject,a,this.eventEmitter),i.createGridAndLabels(d,g,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&O(d,o,a.classNames.gridBackground,this.eventEmitter),b.raw.series.forEach(function(c,d){var g,h,k=d-(b.raw.series.length-1)/2;g=a.distributeSeries&&!a.stackBars?l.axisLength/b.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/b.normalized.series[d].length/2,h=f.elem("g"),h.attr({"ct:series-name":c.name,"ct:meta":w(c.meta)}),h.addClass([a.classNames.series,c.className||a.classNames.series+"-"+j(d)].join(" ")),b.normalized.series[d].forEach(function(f,j){var p,s,t,u;if(u=a.distributeSeries&&!a.stackBars?d:a.distributeSeries&&a.stackBars?0:j,p=a.horizontalBars?{x:o.x1+i.projectValue(f&&f.x?f.x:0,j,b.normalized.series[d]),y:o.y1-l.projectValue(f&&f.y?f.y:0,u,b.normalized.series[d])}:{x:o.x1+l.projectValue(f&&f.x?f.x:0,u,b.normalized.series[d]),y:o.y1-i.projectValue(f&&f.y?f.y:0,j,b.normalized.series[d])},l instanceof pa&&(l.options.stretch||(p[l.units.pos]+=g*(a.horizontalBars?-1:1)),p[l.units.pos]+=a.stackBars||a.distributeSeries?0:k*a.seriesBarDistance*(a.horizontalBars?-1:1)),t=r[j]||q,r[j]=t-(q-p[l.counterUnits.pos]),void 0!==f){var x={};x[l.units.pos+"1"]=p[l.units.pos],x[l.units.pos+"2"]=p[l.units.pos],!a.stackBars||"accumulate"!==a.stackMode&&a.stackMode?(x[l.counterUnits.pos+"1"]=q,x[l.counterUnits.pos+"2"]=p[l.counterUnits.pos]):(x[l.counterUnits.pos+"1"]=t,x[l.counterUnits.pos+"2"]=r[j]),x.x1=Math.min(Math.max(x.x1,o.x1),o.x2),x.x2=Math.min(Math.max(x.x2,o.x1),o.x2),x.y1=Math.min(Math.max(x.y1,o.y2),o.y1),x.y2=Math.min(Math.max(x.y2,o.y2),o.y1);var y=z(c,j);s=h.elem("line",x,a.classNames.bar).attr({"ct:value":[f.x,f.y].filter(e).join(","),"ct:meta":w(y)}),this.eventEmitter.emit("draw",v({type:"bar",value:f,index:j,meta:y,series:c,seriesIndex:d,axisX:m,axisY:n,chartRect:o,group:h,element:s},x))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:i.bounds,chartRect:o,axisX:m,axisY:n,svg:this.svg,options:a})}}]),b}(ha),ya={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:k,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1},za=function(a){function b(a,c,d,e){return ba(this,b),ia(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,a,c,ya,v({},ya,d),e))}return ja(b,a),ca(b,[{key:"createChart",value:function(a){var b,c,d,e,g,h=y(this.data),k=[],l=a.startAngle;this.svg=K(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),c=M(this.svg,a,ya.padding),d=Math.min(c.width()/2,c.height()/2),g=a.total||h.normalized.series.reduce(function(a,b){return a+b},0);var m=i(a.donutWidth);"%"===m.unit&&(m.value*=d/100),d-=a.donut?m.value/2:0,e="outside"===a.labelPosition||a.donut?d:"center"===a.labelPosition?0:d/2,e+=a.labelOffset;var n={x:c.x1+c.width()/2,y:c.y2+c.height()/2},o=1===h.raw.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;h.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)),h.raw.series.forEach(function(c,i){if(0!==h.normalized.series[i]||!a.ignoreEmptyValues){k[i].attr({"ct:series-name":c.name}),k[i].addClass([a.classNames.series,c.className||a.classNames.series+"-"+j(i)].join(" "));var p=g>0?l+h.normalized.series[i]/g*360:0,q=Math.max(0,l-(0===i||o?0:.2));p-q>=359.99&&(p=q+359.99);var r=u(n.x,n.y,d,q),s=u(n.x,n.y,d,p),t=new sa(!a.donut).move(s.x,s.y).arc(d,d,0,p-l>180,0,r.x,r.y);a.donut||t.line(n.x,n.y);var v=k[i].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(v.attr({"ct:value":h.normalized.series[i],"ct:meta":w(c.meta)}),a.donut&&v.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:h.normalized.series[i],totalDataSum:g,index:i,meta:c.meta,series:c,group:k[i],element:v,path:t.clone(),center:n,radius:d,startAngle:l,endAngle:p}),a.showLabel){var x;x=1===h.raw.series.length?{x:n.x,y:n.y}:u(n.x,n.y,e,l+(p-l)/2);var y;y=h.normalized.labels&&!f(h.normalized.labels[i])?h.normalized.labels[i]:h.normalized.series[i];var z=a.labelInterpolationFnc(y,i);if(z||0===z){var A=b.elem("text",{dx:x.x,dy:x.y,"text-anchor":Y(n,x,a.labelDirection)},a.classNames.label).text(""+z);this.eventEmitter.emit("draw",{type:"label",index:i,group:b,element:A,text:""+z,x:x.x,y:x.y})}}l=p}}.bind(this)),this.eventEmitter.emit("created",{chartRect:c,svg:this.svg,options:a})}}]),b}(ha);a.Interpolation=ta,a.EventEmitter=ga,a.extend=v,a.optionsProvider=Q,a.namespaces=$,a.precision=_,a.escapingMap=aa,a.version=Z,a.replaceAll=b,a.querySelector=c,a.safeHasProperty=d,a.isNumeric=e,a.isFalseyButZero=f,a.getNumberOrUndefined=g,a.ensureUnit=h,a.quantity=i,a.alphaNumerate=j,a.noop=k,a.times=l,a.sum=m,a.mapMultiply=n,a.mapAdd=o,a.serialMap=p,a.orderOfMagnitude=q,a.projectLength=r,a.roundWithPrecision=s,a.rho=t,a.polarToCartesian=u,a.serialize=w,a.deserialize=x,a.normalizeData=y,a.getMetaData=z,a.isDataHoleValue=A,a.reverseData=B,a.getDataArray=C,a.isMultiValue=D,a.getMultiValue=E,a.getSeriesOption=F,a.splitIntoSegments=G,a.getHighLow=H,a.getBounds=I,a.createSvg=K,a.normalizePadding=L,a.createChartRect=M,a.createGrid=N,a.createGridBackground=O,a.createLabel=P,a.BaseChart=ha,a.LineChart=va,a.BarChart=xa,a.PieChart=za,a.Axis=la,a.axisUnits=ka,a.AutoScaleAxis=na,a.FixedScaleAxis=oa,a.StepAxis=pa,a.Svg=ea,a.isSupported=J,a.easings=fa,a.SvgList=da,a.SvgPath=sa,Object.defineProperty(a,"__esModule",{value:!0})}); +!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?b(exports):"function"==typeof define&&define.amd?define(["exports"],b):b(a.Chartist=a.Chartist||{})}(this,function(a){"use strict";function b(a,b,c){return a.replace(new RegExp(b,"g"),c)}function c(a){return a instanceof Node?a:document.querySelector(a)}function d(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)}function e(a){return null!==a&&isFinite(a)}function f(a){return!a&&0!==a}function g(a){return e(a)?+a:void 0}function h(a,b){return"number"==typeof a&&(a+=b),a}function i(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}}function j(a){return String.fromCharCode(97+a%26)}function k(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)}function l(a,b,c){return b/c.range*a}function m(a,b){var c=Math.pow(10,b||V);return Math.round(a*c)/c}function n(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=2,e=2,f=void 0;if(a%2===0)return 2;do d=c(d)%a,e=c(c(e))%a,f=b(Math.abs(d-e),a);while(1===f);return f}function o(a,b,c,d){var e=(d-90)*Math.PI/180;return{x:a+c*Math.cos(e),y:b+c*Math.sin(e)}}function p(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};a=a||{};for(var b=arguments.length,c=Array(b>1?b-1:0),d=1;d1&&void 0!==arguments[1]?arguments[1]:"y";return g(x(a)?a[b]:a)}function z(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]}function A(a,b,c){var d={increasingX:!1,fillHoles:!1};c=p({},d,c);for(var e=[],f=!0,g=0;g=2&&a[g]<=a[g-2]&&(f=!0),f&&(e.push({pathCoordinates:[],valueData:[]}),f=!1),e[e.length-1].pathCoordinates.push(a[g],a[g+1]),e[e.length-1].valueData.push(b[g/2]));return e}function B(a,b,c){function d(a){if(void 0!==a)if(a instanceof Array)for(var b=0;be.high&&(e.high=h),g&&h0?e.low=0:(e.high=1,e.low=0)),e}function C(a,b,c,d){function e(a,b){return a===(a+=b)&&(a*=1+(b>0?aa:-aa)),a}var f={high:b.high,low:b.low};f.valueRange=f.high-f.low,f.oom=k(f.valueRange),f.step=Math.pow(10,f.oom),f.min=Math.floor(f.low/f.step)*f.step,f.max=Math.ceil(f.high/f.step)*f.step,f.range=f.max-f.min,f.numberOfSteps=Math.round(f.range/f.step);var g=l(a,f.step,f),h=g=c)f.step=1;else if(d&&i=c)f.step=i;else for(var j=0;;){if(h&&l(a,f.step,f)<=c)f.step*=2;else{if(h||!(l(a,f.step/2,f)>=c))break;if(f.step/=2,d&&f.step%1!==0){f.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}f.step=Math.max(f.step,aa);for(var o=f.min,p=f.max;o+f.step<=f.low;)o=e(o,f.step);for(;p-f.step>=f.high;)p=e(p,-f.step);f.min=o,f.max=p,f.range=f.max-f.min;for(var q=[],r=f.min;r<=f.max;r=e(r,f.step)){var s=m(r);s!==q[q.length-1]&&q.push(s)}return f.values=q,f}function D(a){return document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#"+a,"1.1")}function E(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"100%",c=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"100%",d=arguments[3];Array.from(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(U.xmlns,"ct")}).forEach(function(b){return a.removeChild(b)});var e=new ea("svg").attr({width:b,height:c}).addClass(d).attr({style:"width: "+b+"; height: "+c+";"});return a.appendChild(e._node),e}function F(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return"number"==typeof a?{top:a,right:a,bottom:a,left:a}:{top:"number"==typeof a.top?a.top:b,right:"number"==typeof a.right?a.right:b,bottom:"number"==typeof a.bottom?a.bottom:b,left:"number"==typeof a.left?a.left:b}}function G(a,b,c){var d=!(!b.axisX&&!b.axisY),e=d?b.axisY.offset:0,f=d?b.axisX.offset:0,g=a.width()||i(b.width).value||0,h=a.height()||i(b.height).value||0,j=F(b.chartPadding,c);g=Math.max(g,e+j.left+j.right),h=Math.max(h,f+j.top+j.bottom);var k={padding:j,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return d?("start"===b.axisX.position?(k.y2=j.top+f,k.y1=Math.max(h-j.bottom,k.y2+1)):(k.y2=j.top,k.y1=Math.max(h-j.bottom-f,k.y2+1)),"start"===b.axisY.position?(k.x1=j.left+e,k.x2=Math.max(g-j.right,k.x1+1)):(k.x1=j.left,k.x2=Math.max(g-j.right-e,k.x1+1))):(k.x1=j.left,k.x2=Math.max(g-j.right,k.x1+1),k.y2=j.top,k.y1=Math.max(h-j.bottom,k.y2+1)),k}function H(a,b,c,d,e,f,g,h){var i={};i[c.units.pos+"1"]=a,i[c.units.pos+"2"]=a,i[c.counterUnits.pos+"1"]=d,i[c.counterUnits.pos+"2"]=d+e;var j=f.elem("line",i,g.join(" "));h.emit("draw",p({type:"grid",axis:c,index:b,group:f,element:j},i))}function I(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})}function J(a,b,c,d,e,f,g,h,i,j,k){var l=void 0,m={};if(m[e.units.pos]=a+g[e.units.pos],m[e.counterUnits.pos]=g[e.counterUnits.pos],m[e.units.len]=b,m[e.counterUnits.len]=Math.max(0,f-10),j){var n=Math.round(m[e.units.len]),o=Math.round(m[e.counterUnits.len]),q=('\n \n '+d[c]+"\n \n ").trim();l=h.foreignObject(q,p({style:"overflow: visible;"},m))}else l=h.elem("text",m,i.join(" ")).text(d[c]);k.emit("draw",p({type:"label",axis:e,index:c,group:h,element:l,text:d[c]},m))}function K(a,b,c){function d(a){var d=g;g=p({},f),b&&b.forEach(function(a){var b=window.matchMedia(a[0]);b.matches&&(g=p(g,a[1]))}),c&&a&&c.emit("optionsChanged",{previousOptions:d,currentOptions:g})}function e(){h.forEach(function(a){return a.removeListener(d)})}var f=p({},a),g=void 0,h=[];if(!window.matchMedia)throw"window.matchMedia not found! Make sure you're using a polyfill.";return b&&b.forEach(function(a){var b=window.matchMedia(a[0]);b.addListener(d),h.push(b)}),d(),{removeMediaQueryListeners:e,getCurrentOptions:function(){return p({},g)}}}function L(a,b,c,d,e,f){var g=p({command:e?a.toLowerCase():a.toUpperCase()},b,f?{data:f}:{});c.splice(d,0,g)}function M(a,b){a.forEach(function(c,d){qa[c.command.toLowerCase()].forEach(function(e,f){b(c,e,d,f,a)})})}function N(a){var b={fillHoles:!1};return a=p({},b,a),function(b,c){for(var d=new sa,e=!0,f=0;f1)return sa.join(g.map(function(a){return b(a.pathCoordinates,a.valueData)}));if(e=g[0].pathCoordinates,f=g[0].valueData,e.length<=4)return N()(e,f);for(var h=(new sa).move(e[0],e[1],!1,f[0]),i=void 0,j=0,k=e.length;k-2*!i>j;j+=2){var l=[{x:+e[j-2],y:+e[j-1]},{x:+e[j],y:+e[j+1]},{x:+e[j+2],y:+e[j+3]},{x:+e[j+4],y:+e[j+5]}];i?j?k-4===j?l[3]={x:+e[0],y:+e[1]}:k-2===j&&(l[2]={x:+e[0],y:+e[1]},l[3]={x:+e[2],y:+e[3]}):l[0]={x:+e[k-2],y:+e[k-1]}:k-4===j?l[3]=l[2]:j||(l[0]={x:+e[j],y:+e[j+1]}),h.curve(c*(-l[0].x+6*l[1].x+l[2].x)/6+d*l[2].x,c*(-l[0].y+6*l[1].y+l[2].y)/6+d*l[2].y,c*(l[1].x+6*l[2].x-l[3].x)/6+d*l[2].x,c*(l[1].y+6*l[2].y-l[3].y)/6+d*l[2].y,l[2].x,l[2].y,!1,f[(j+2)/2])}return h}return N()([])}}function R(a){var b={fillHoles:!1};return a=p({},b,a),function b(c,d){var e=A(c,d,{fillHoles:a.fillHoles,increasingX:!0});if(e.length){if(e.length>1)return sa.join(e.map(function(a){return b(a.pathCoordinates,a.valueData)}));if(c=e[0].pathCoordinates,d=e[0].valueData,c.length<=4)return N()(c,d);for(var f=[],g=[],h=c.length/2,i=[],j=[],k=[],l=[],m=0;m0!=j[o]>0?i[o]=0:(i[o]=3*(l[o-1]+l[o])/((2*l[o]+l[o-1])/j[o-1]+(l[o]+2*l[o-1])/j[o]),isFinite(i[o])||(i[o]=0));for(var p=(new sa).move(f[0],g[0],!1,d[0]),q=0;qa.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}var T="1.0.0",U={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"},V=8,W={"&":"&","<":"<",">":">",'"':""","'":"'"},X=function(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b1}).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,f).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,f)}).forEach(function(e){var f=l.elem("path",{d:e.stringify()},a.classNames.area,!0);b.eventEmitter.emit("draw",{type:"area",values:c.normalized.series[g],path:e.clone(),series:d,seriesIndex:g,axisX:i,axisY:k,chartRect:h,index:g,group:l,element:f})})}()}),this.eventEmitter.emit("created",{bounds:k.bounds,chartRect:h,axisX:i,axisY:k,svg:this.svg,options:a})}}]),b}(ha),wa={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:Y,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:Y,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"}},xa=function(a){function b(a,c,d,e){return ba(this,b),ia(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,a,c,wa,p({},wa,d),e))}return ja(b,a),ca(b,[{key:"createChart",value:function(a){var b=arguments,c=this,d=void 0,f=void 0;a.distributeSeries?(d=s(this.data,a.reverseData,a.horizontalBars?"x":"y"),d.normalized.series=d.normalized.series.map(function(a){return[a]})):d=s(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=E(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var g=this.svg.elem("g").addClass(a.classNames.gridGroup),h=this.svg.elem("g"),i=this.svg.elem("g").addClass(a.classNames.labelGroup);if(a.stackBars&&0!==d.normalized.series.length){var k=_(d.normalized.series,function(){return Array.from(b).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})});f=B([k],a,a.horizontalBars?"x":"y")}else f=B(d.normalized.series,a,a.horizontalBars?"x":"y");f.high=+a.high||(0===a.high?0:f.high),f.low=+a.low||(0===a.low?0:f.low);var l=G(this.svg,a,wa.padding),m=void 0,n=void 0,o=void 0,r=void 0,u=void 0;n=a.distributeSeries&&a.stackBars?d.normalized.labels.slice(0,1):d.normalized.labels,a.horizontalBars?(m=r=void 0===a.axisX.type?new na(ka.x,d.normalized.series,l,p({},a.axisX,{highLow:f,referenceValue:0})):new a.axisX.type(ka.x,d.normalized.series,l,p({},a.axisX,{highLow:f,referenceValue:0})),o=u=void 0===a.axisY.type?new pa(ka.y,d.normalized.series,l,{ticks:n}):new a.axisY.type(ka.y,d.normalized.series,l,a.axisY)):(o=r=void 0===a.axisX.type?new pa(ka.x,d.normalized.series,l,{ticks:n}):new a.axisX.type(ka.x,d.normalized.series,l,a.axisX),m=u=void 0===a.axisY.type?new na(ka.y,d.normalized.series,l,p({},a.axisY,{highLow:f,referenceValue:0})):new a.axisY.type(ka.y,d.normalized.series,l,p({},a.axisY,{highLow:f,referenceValue:0})));var v=a.horizontalBars?l.x1+m.projectValue(0):l.y1-m.projectValue(0),w=[];o.createGridAndLabels(g,i,this.supportsForeignObject,a,this.eventEmitter),m.createGridAndLabels(g,i,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&I(g,l,a.classNames.gridBackground,this.eventEmitter),d.raw.series.forEach(function(b,f){var g=f-(d.raw.series.length-1)/2,i=void 0;i=a.distributeSeries&&!a.stackBars?o.axisLength/d.normalized.series.length/2:a.distributeSeries&&a.stackBars?o.axisLength/2:o.axisLength/d.normalized.series[f].length/2;var k=h.elem("g");k.attr({"ct:series-name":b.name,"ct:meta":q(b.meta)}),k.addClass([a.classNames.series,b.className||a.classNames.series+"-"+j(f)].join(" ")),d.normalized.series[f].forEach(function(h,j){var n=void 0;n=a.distributeSeries&&!a.stackBars?f:a.distributeSeries&&a.stackBars?0:j;var s=void 0;s=a.horizontalBars?{x:l.x1+m.projectValue(h&&h.x?h.x:0,j,d.normalized.series[f]),y:l.y1-o.projectValue(h&&h.y?h.y:0,n,d.normalized.series[f])}:{x:l.x1+o.projectValue(h&&h.x?h.x:0,n,d.normalized.series[f]),y:l.y1-m.projectValue(h&&h.y?h.y:0,j,d.normalized.series[f])},o instanceof pa&&(o.options.stretch||(s[o.units.pos]+=i*(a.horizontalBars?-1:1)),s[o.units.pos]+=a.stackBars||a.distributeSeries?0:g*a.seriesBarDistance*(a.horizontalBars?-1:1));var x=w[j]||v;if(w[j]=x-(v-s[o.counterUnits.pos]),void 0!==h){var y={};y[o.units.pos+"1"]=s[o.units.pos],y[o.units.pos+"2"]=s[o.units.pos],!a.stackBars||"accumulate"!==a.stackMode&&a.stackMode?(y[o.counterUnits.pos+"1"]=v,y[o.counterUnits.pos+"2"]=s[o.counterUnits.pos]):(y[o.counterUnits.pos+"1"]=x,y[o.counterUnits.pos+"2"]=w[j]),y.x1=Math.min(Math.max(y.x1,l.x1),l.x2),y.x2=Math.min(Math.max(y.x2,l.x1),l.x2),y.y1=Math.min(Math.max(y.y1,l.y2),l.y1),y.y2=Math.min(Math.max(y.y2,l.y2),l.y1);var z=t(b,j),A=k.elem("line",y,a.classNames.bar).attr({"ct:value":[h.x,h.y].filter(e).join(","),"ct:meta":q(z)});c.eventEmitter.emit("draw",p({type:"bar",value:h,index:j,meta:z,series:b,seriesIndex:f,axisX:r,axisY:u,chartRect:l,group:k,element:A},y))}})}),this.eventEmitter.emit("created",{bounds:m.bounds,chartRect:l,axisX:r,axisY:u,svg:this.svg,options:a})}}]),b}(ha),ya={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:Y,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1},za=function(a){function b(a,c,d,e){return ba(this,b),ia(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,a,c,ya,p({},ya,d),e))}return ja(b,a),ca(b,[{key:"createChart",value:function(a){var b=this,c=s(this.data),d=[],e=void 0,g=void 0,h=a.startAngle;this.svg=E(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie);var k=G(this.svg,a,ya.padding),l=Math.min(k.width()/2,k.height()/2),m=a.total||c.normalized.series.reduce($,0),n=i(a.donutWidth);"%"===n.unit&&(n.value*=l/100),l-=a.donut?n.value/2:0,g="outside"===a.labelPosition||a.donut?l:"center"===a.labelPosition?0:l/2,g+=a.labelOffset;var p={x:k.x1+k.width()/2,y:k.y2+k.height()/2},r=1===c.raw.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;c.raw.series.forEach(function(a,c){return d[c]=b.svg.elem("g",null,null)}),a.showLabel&&(e=this.svg.elem("g",null,null)),c.raw.series.forEach(function(i,k){if(0!==c.normalized.series[k]||!a.ignoreEmptyValues){d[k].attr({"ct:series-name":i.name}),d[k].addClass([a.classNames.series,i.className||a.classNames.series+"-"+j(k)].join(" "));var s=m>0?h+c.normalized.series[k]/m*360:0,t=Math.max(0,h-(0===k||r?0:.2));s-t>=359.99&&(s=t+359.99);var u=o(p.x,p.y,l,t),v=o(p.x,p.y,l,s),w=new sa(!a.donut).move(v.x,v.y).arc(l,l,0,s-h>180,0,u.x,u.y);a.donut||w.line(p.x,p.y);var x=d[k].elem("path",{d:w.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(x.attr({"ct:value":c.normalized.series[k],"ct:meta":q(i.meta)}),a.donut&&x.attr({style:"stroke-width: "+n.value+"px"}),b.eventEmitter.emit("draw",{type:"slice",value:c.normalized.series[k],totalDataSum:m,index:k,meta:i.meta,series:i,group:d[k],element:x,path:w.clone(),center:p,radius:l,startAngle:h,endAngle:s}),a.showLabel){var y=void 0;y=1===c.raw.series.length?{x:p.x,y:p.y}:o(p.x,p.y,g,h+(s-h)/2);var z=void 0;z=c.normalized.labels&&!f(c.normalized.labels[k])?c.normalized.labels[k]:c.normalized.series[k];var A=a.labelInterpolationFnc(z,k);if(A||0===A){var B=e.elem("text",{dx:y.x,dy:y.y,"text-anchor":S(p,y,a.labelDirection)},a.classNames.label).text(""+A);b.eventEmitter.emit("draw",{type:"label",index:k,group:e,element:B,text:""+A,x:y.x,y:y.y})}}h=s}}),this.eventEmitter.emit("created",{chartRect:k,svg:this.svg,options:a})}}]),b}(ha);a.Interpolation=ta,a.EventEmitter=ga,a.extend=p,a.optionsProvider=K,a.namespaces=U,a.precision=V,a.escapingMap=W,a.version=T,a.replaceAll=b,a.querySelector=c,a.safeHasProperty=d,a.isNumeric=e,a.isFalseyButZero=f,a.getNumberOrUndefined=g,a.ensureUnit=h,a.quantity=i,a.alphaNumerate=j,a.noop=Y,a.times=Z,a.sum=$,a.serialMap=_,a.EPSILON=aa,a.orderOfMagnitude=k,a.projectLength=l,a.roundWithPrecision=m,a.rho=n,a.polarToCartesian=o,a.serialize=q,a.deserialize=r,a.normalizeData=s,a.getMetaData=t,a.isDataHoleValue=u,a.reverseData=v,a.getDataArray=w,a.isMultiValue=x,a.getMultiValue=y,a.getSeriesOption=z,a.splitIntoSegments=A,a.getHighLow=B,a.getBounds=C,a.createSvg=E,a.normalizePadding=F,a.createChartRect=G,a.createGrid=H,a.createGridBackground=I,a.createLabel=J,a.BaseChart=ha,a.LineChart=va,a.BarChart=xa,a.PieChart=za,a.Axis=la,a.axisUnits=ka,a.AutoScaleAxis=na,a.FixedScaleAxis=oa,a.StepAxis=pa,a.Svg=ea,a.isSupported=D,a.easings=fa,a.SvgList=da,a.SvgPath=sa,Object.defineProperty(a,"__esModule",{value:!0})}); //# sourceMappingURL=chartist.umd.js.map \ No newline at end of file diff --git a/dist/chartist.umd.js.map b/dist/chartist.umd.js.map index a26d78b8..317abd6d 100644 --- a/dist/chartist.umd.js.map +++ b/dist/chartist.umd.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/core/lang.js","../src/core/functional.js","../src/core/math.js","../src/core/extend.js","../src/core/data.js","../src/svg/svg.js","../src/core/creation.js","../src/core/options-provider.js","../src/svg/svg-path.js","../src/interpolation/none.js","../src/interpolation/simple.js","../src/interpolation/step.js","../src/interpolation/cardinal.js","../src/interpolation/monotone-cubic.js","../src/charts/pie.js","../package.json!file:/home/gion/Code/chartist/tooling/system-loaders/package.json","../src/core/globals.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/classCallCheck.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/createClass.js","../src/svg/svg-list.js","../src/event/event-emitter.js","../src/charts/base.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/possibleConstructorReturn.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/inherits.js","../src/axes/axis.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/get.js","../src/axes/auto-scale-axis.js","../src/axes/fixed-scale-axis.js","../src/axes/step-axis.js","../src/charts/line.js","../src/charts/bar.js"],"names":["replaceAll","str","subStr","newSubStr","replace","RegExp","querySelector","query","Node","document","safeHasProperty","object","property","hasOwnProperty","isNumeric","value","isFinite","isFalseyButZero","getNumberOrUndefined","undefined","ensureUnit","unit","quantity","input","match","exec","alphaNumerate","n","String","fromCharCode","noop","times","length","Array","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","forEach","index","args","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","roundWithPrecision","digits","precision","pow","round","rho","gcd","p","q","f","x","divisor","x1","x2","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","extend","target","i","source","sourceProp","arguments","prop","serialize","data","JSON","stringify","Object","keys","escapingMap","reduce","key","deserialize","parse","normalizeData","reverse","multi","labelCount","output","normalized","series","getDataArray","every","labels","slice","prototype","push","getMetaData","meta","isDataHoleValue","isNaN","reverseData","recursiveConvert","multiValue","y","isMultiValue","getMultiValue","dimension","getSeriesOption","options","name","seriesOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","segments","hole","fillHoles","increasingX","getHighLow","recursiveHighLow","findHigh","highLow","high","findLow","low","toUpperCase","Number","MAX_VALUE","referenceValue","min","getBounds","scaleMinSpace","onlyInteger","safeIncrement","increment","EPSILON","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","isSupported","feature","implementation","hasFeature","createSvg","container","width","height","className","svg","call","querySelectorAll","filter","getAttributeNS","namespaces","xmlns","removeChild","Svg","attr","addClass","appendChild","_node","normalizePadding","padding","fallback","top","right","bottom","left","createChartRect","fallbackPadding","hasAxis","axisX","axisY","yAxisOffset","offset","xAxisOffset","normalizedPadding","chartPadding","chartRect","this","y1","y2","position","createGrid","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","optionsProvider","responsiveOptions","updateCurrentOptions","mediaEvent","previousOptions","currentOptions","baseOptions","mql","window","matchMedia","matches","removeMediaQueryListeners","removeListener","mediaQueryListeners","addListener","element","command","params","pathElements","relative","pathElement","toLowerCase","splice","forEachParam","pathElementIndex","paramName","paramIndex","none","path","SvgPath","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","postpone","cardinal","t","tension","c","paths","segment","z","iLen","monotoneCubic","xs","ys","ms","ds","dys","dxs","determineAnchorPosition","center","label","direction","toTheRight","version","_classCallCheck","instance","Constructor","TypeError","_createClass","defineProperties","props","descriptor","enumerable","configurable","writable","defineProperty","protoProps","staticProps","SvgList","nodeList","list","svgElements","prototypeProperty","indexOf","attributes","parent","insertFirst","Element","createElementNS","ct","firstChild","insertBefore","ns","getAttribute","namespacedAttribute","split","setAttributeNS","setAttribute","bind","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","createElement","innerHTML","fnObj","createTextNode","newElement","replaceChild","trim","names","concat","self","removedClasses","getBoundingClientRect","animations","guided","attribute","createAnimate","animationDefinition","animate","timeout","animationEasing","attributeProperties","easing","easings","begin","dur","calcMode","keySplines","keyTimes","fill","from","beginElement","err","to","remove","addEventListener","EventEmitter","handlers","event","handler","starHandler","BaseChart","supportsForeignObject","supportsAnimations","resizeListener","update","__chartist__","detach","initializeTimeoutId","setTimeout","initialize","override","createChart","getCurrentOptions","clearTimeout","removeEventListener","addEventHandler","removeEventHandler","plugins","plugin","_possibleConstructorReturn","ReferenceError","_inherits","subClass","superClass","create","setPrototypeOf","__proto__","axisUnits","Axis","ticks","rectEnd","rectStart","gridOffset","rectOffset","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","_get","get","receiver","Function","desc","getOwnPropertyDescriptor","getPrototypeOf","getter","AutoScaleAxis","_Axis","axisUnit","_this","FixedScaleAxis","sort","a","b","stepLength","StepAxis","calc","stretch","elementDescriptions","close","joinedPath","j","count","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","transformFnc","transformed","LineChart","_BaseChart","chart","seriesGroup","type","fullWidth","createGridAndLabels","showGridBackground","raw","seriesIndex","seriesElement","pathData","valueIndex","smoothing","lineSmooth","showPoint","point","showLine","clone","showArea","areaBase","areaBaseProjected","splitByCommand","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","BarChart","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","stackMode","metaData","PieChart","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","start","end","arc","sliceDonut","slicePie","rawValue","interpolatedValue","labelDirection"],"mappings":"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","file":"chartist.umd.js","sourcesContent":["/**\n * Replaces all occurrences of subStr in str with newSubStr and returns a new string.\n *\n * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @return {String}\n */\nexport function replaceAll(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\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 */\nexport function querySelector(query) {\n return query instanceof Node ? query : document.querySelector(query);\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 */\nexport function safeHasProperty(object, property) {\n return object !== null &&\n typeof object === 'object' &&\n object.hasOwnProperty(property);\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 */\nexport function isNumeric(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 */\nexport function isFalseyButZero(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 */\nexport function getNumberOrUndefined(value) {\n return isNumeric(value) ? +value : undefined;\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 */\nexport function ensureUnit(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 */\nexport function quantity(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 * 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 */\nexport function alphaNumerate(n) {\n // Limit to a-z\n return String.fromCharCode(97 + n % 26);\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 */\nexport function noop(n) {\n return n;\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 */\nexport function times(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 */\nexport function sum(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 */\nexport function mapMultiply(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 */\nexport function mapAdd(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 */\nexport function serialMap(arr, cb) {\n var result = [],\n length = Math.max.apply(null, arr.map(function(e) {\n return e.length;\n }));\n\n 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","import {precision} from './globals';\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 */\nexport function orderOfMagnitude(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 */\nexport function projectLength(axisLength, length, bounds) {\n return length / bounds.range * axisLength;\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 */\nexport function roundWithPrecision(value, digits) {\n var precision = Math.pow(10, digits || precision);\n return Math.round(value * precision) / precision;\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 */\nexport function rho(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 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 */\nexport function polarToCartesian(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 * 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 */\nexport function extend(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] = extend(target[prop], sourceProp);\n } else {\n target[prop] = sourceProp;\n }\n }\n }\n\n return target;\n}\n","import {escapingMap} from './globals';\nimport {replaceAll, safeHasProperty, getNumberOrUndefined} from './lang';\nimport {times} from './functional';\nimport {extend} from './extend';\nimport {orderOfMagnitude, projectLength, roundWithPrecision, rho} from './math';\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 */\nexport function serialize(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(escapingMap).reduce(function(result, key) {\n return replaceAll(result, key, 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 */\nexport function deserialize(data) {\n if(typeof data !== 'string') {\n return data;\n }\n\n data = Object.keys(escapingMap).reduce(function(result, key) {\n return replaceAll(result, 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 * 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 */\nexport function normalizeData(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 = 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 times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() {\n return '';\n })\n );\n\n if(reverse) {\n reverseData(output.normalized);\n }\n\n return output;\n}\n\n/**\n * Get meta data of a specific value in a series.\n *\n * @param series\n * @param index\n * @returns {*}\n */\nexport function getMetaData(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? value.meta : undefined;\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 */\nexport function isDataHoleValue(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 */\nexport function reverseData(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 */\nexport function getDataArray(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(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(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(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] = getNumberOrUndefined(value);\n } else {\n multiValue.y = getNumberOrUndefined(value);\n }\n\n multiValue.x = value.hasOwnProperty('x') ? getNumberOrUndefined(value.x) : multiValue.x;\n multiValue.y = value.hasOwnProperty('y') ? getNumberOrUndefined(value.y) : multiValue.y;\n\n return multiValue;\n\n } else {\n // We can return simple data\n return getNumberOrUndefined(value);\n }\n }\n }\n\n return data.series.map(recursiveConvert);\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 */\nexport function isMultiValue(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 */\nexport function getMultiValue(value, dimension) {\n if(isMultiValue(value)) {\n return getNumberOrUndefined(value[dimension || 'y']);\n } else {\n return getNumberOrUndefined(value);\n }\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 */\nexport function getSeriesOption(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 * 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} valueData 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 */\nexport function splitIntoSegments(pathCoordinates, valueData, options) {\n var defaultOptions = {\n increasingX: false,\n fillHoles: false\n };\n\n options = 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(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\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 */\nexport function getHighLow(data, options, dimension) {\n // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred\n options = 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 * 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 */\nexport function getBounds(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 = 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 = projectLength(axisLength, bounds.step, bounds);\n var scaleUp = length < scaleMinSpace;\n var smallestFactor = onlyInteger ? 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 && projectLength(axisLength, 1, bounds) >= scaleMinSpace) {\n bounds.step = 1;\n } else if(onlyInteger && smallestFactor < bounds.step && 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 && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && 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 value *= (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 newMin = safeIncrement(newMin, bounds.step);\n }\n while (newMax - bounds.step >= bounds.high) {\n newMax = 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 = roundWithPrecision(i);\n if (value !== values[values.length - 1]) {\n values.push(i);\n }\n }\n bounds.values = values;\n return bounds;\n}\n","import {namespaces, ensureUnit, quantity, extend} from '../core/core';\nimport {SvgList} from './svg-list';\n\n/**\n * 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 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 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 */\nexport class Svg {\n\n constructor(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(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': 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 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 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(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 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 {Svg} Returns a Svg wrapper object that can be used to modify the containing SVG data\n */\n elem(name, attributes, className, insertFirst) {\n return new Svg(name, attributes, className, this, insertFirst);\n }\n\n /**\n * Returns the parent Chartist.SVG wrapper object\n *\n * @memberof Svg\n * @return {Svg} Returns a 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 parent() {\n return this._node.parentNode instanceof SVGElement ? new Svg(this._node.parentNode) : null;\n }\n\n /**\n * This method returns a Svg wrapper around the root SVG element of the current tree.\n *\n * @memberof Svg\n * @return {Svg} The root SVG element wrapped in a Svg element\n */\n root() {\n var node = this._node;\n while(node.nodeName !== 'svg') {\n node = node.parentNode;\n }\n return new 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 Svg wrapper.\n *\n * @memberof Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {Svg} The SVG wrapper for the element found or null if no element was found\n */\n querySelector(selector) {\n var foundNode = this._node.querySelector(selector);\n return foundNode ? new 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 Svg.List wrapper.\n *\n * @memberof Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {SvgList} The SVG wrapper list for the element found or null if no element was found\n */\n querySelectorAll(selector) {\n var foundNodes = this._node.querySelectorAll(selector);\n return foundNodes.length ? new SvgList(foundNodes) : null;\n }\n\n /**\n * Returns the underlying SVG node for the current element.\n *\n * @memberof Svg\n * @returns {Node}\n */\n 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 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 {Svg} New wrapper object that wraps the foreignObject element\n */\n 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', 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 Svg wrapper.\n *\n * @memberof Svg\n * @param {String} t The text that should be added to the text element that is created\n * @return {Svg} The same wrapper object that was used to add the newly created element\n */\n 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 Svg\n * @return {Svg} The same wrapper object that got emptied\n */\n 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 Svg\n * @return {Svg} The parent wrapper object of the element that got removed\n */\n 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 Svg\n * @param {Svg} newElement The new Svg object that will be used to replace the current wrapper object\n * @return {Svg} The wrapper of the new element\n */\n 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 Svg\n * @param {Svg} element The 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 {Svg} The wrapper of the appended object\n */\n 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 Svg\n * @return {Array} A list of classes or an empty array if there are no classes on the current element\n */\n 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 Svg\n * @param {String} names A white space separated list of class names\n * @return {Svg} The wrapper of the current element\n */\n addClass(names) {\n this._node.setAttribute('class',\n this.classes()\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 Svg\n * @param {String} names A white space separated list of class names\n * @return {Svg} The wrapper of the current element\n */\n removeClass(names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n this._node.setAttribute('class', this.classes().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 Svg\n * @return {Svg} The wrapper of the current element\n */\n removeAllClasses() {\n this._node.setAttribute('class', '');\n return this;\n }\n\n /**\n * Get element height using `getBoundingClientRect`\n *\n * @memberof Svg\n * @return {Number} The elements height in pixels\n */\n 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 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 `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 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 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 {Svg} The current element where the animation was added\n */\n 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 animationEasing;\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 animationEasing = animationDefinition.easing instanceof Array ?\n animationDefinition.easing :\n easings[animationDefinition.easing];\n delete animationDefinition.easing;\n }\n\n // If numeric dur or begin was provided we assume milli seconds\n animationDefinition.begin = ensureUnit(animationDefinition.begin, 'ms');\n animationDefinition.dur = ensureUnit(animationDefinition.dur, 'ms');\n\n if(animationEasing) {\n animationDefinition.calcMode = 'spline';\n animationDefinition.keySplines = animationEasing.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 = quantity(animationDefinition.begin || 0).value;\n animationDefinition.begin = 'indefinite';\n }\n\n animate = this.elem('animate', 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\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 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 */\nexport function isSupported(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 `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 Svg\n */\nexport const easings = {\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","import {namespaces} from './globals';\nimport {Svg} from '../svg/svg';\nimport {quantity} from './lang';\nimport {extend} from './extend';\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 */\nexport function createSvg(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(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 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 * 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 */\nexport function normalizePadding(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/**\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 */\nexport function createChartRect(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() || quantity(options.width).value || 0;\n var height = svg.height() || quantity(options.height).value || 0;\n var normalizedPadding = 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 */\nexport function createGrid(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 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 */\nexport function createGridBackground(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 */\nexport function createLabel(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, 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', extend({\n type: 'label',\n axis: axis,\n index: index,\n group: group,\n element: labelElement,\n text: labels[index]\n }, positionalData));\n}\n","import {extend} from './extend';\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 */\nexport function optionsProvider(options, responsiveOptions, eventEmitter) {\n var baseOptions = extend({}, options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions(mediaEvent) {\n var previousOptions = currentOptions;\n currentOptions = 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 = 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 extend({}, currentOptions);\n }\n };\n}\n","import {extend} from '../core/core';\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 SvgPath\n * @type {Object}\n */\nconst 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 SvgPath\n * @type {Object}\n */\nconst 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\nfunction element(command, params, pathElements, pos, relative, data) {\n var pathElement = extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params, data ? { data: data } : {} );\n\n pathElements.splice(pos, 0, pathElement);\n}\n\nfunction 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 SvgPath\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 */\nexport class SvgPath {\n /**\n * This static function on `SvgPath` is joining multiple paths together into one paths.\n *\n * @memberof SvgPath\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 {SvgPath}\n */\n static join(paths, close, options) {\n var joinedPath = new SvgPath(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 constructor(close, options) {\n this.pathElements = [];\n this.pos = 0;\n this.close = close;\n this.options = 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 SvgPath\n * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array.\n * @return {SvgPath|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 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 SvgPath\n * @param {Number} count Number of path elements that should be removed from the current position.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\n * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n 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 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 SvgPath\n * @return {String}\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\n * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath}\n */\n clone(close) {\n var c = new SvgPath(close || this.close);\n c.pos = this.pos;\n c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) {\n return extend({}, pathElement);\n });\n c.options = 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 SvgPath\n * @param {String} command The command you'd like to use to split the path\n * @return {Array}\n */\n splitByCommand(command) {\n var split = [\n new SvgPath()\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 SvgPath());\n }\n\n split[split.length - 1].pathElements.push(pathElement);\n });\n\n return split;\n }\n}\n","import {extend, getMultiValue} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function none(options) {\n var defaultOptions = {\n fillHoles: false\n };\n options = extend({}, defaultOptions, options);\n return function none(pathCoordinates, valueData) {\n var path = new SvgPath();\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(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","import {extend} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function simple(options) {\n var defaultOptions = {\n divisor: 2,\n fillHoles: false\n };\n options = extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates, valueData) {\n var path = new SvgPath();\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","import {extend} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function step(options) {\n var defaultOptions = {\n postpone: true,\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new SvgPath();\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","import {extend, splitIntoSegments} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\nimport {none} from './none';\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 */\nexport function cardinal(options) {\n var defaultOptions = {\n tension: 1,\n fillHoles: false\n };\n\n options = 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 = splitIntoSegments(pathCoordinates, valueData, {\n fillHoles: options.fillHoles\n });\n\n if(!segments.length) {\n // If there were no segments return 'none' interpolation\n return 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 SvgPath.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 none()(pathCoordinates, valueData);\n }\n\n var path = new SvgPath().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","import {extend, splitIntoSegments} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\nimport {none} from './none';\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 */\nexport function monotoneCubic(options) {\n var defaultOptions = {\n fillHoles: false\n };\n\n options = 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 = 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 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 SvgPath.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 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 SvgPath().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","import {alphaNumerate, quantity, isFalseyButZero} from '../core/lang';\nimport {noop} from '../core/functional';\nimport {polarToCartesian} from '../core/math';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize} from '../core/data';\nimport {createSvg, createChartRect} from '../core/creation';\nimport {SvgPath} from '../svg/svg-path';\nimport {BaseChart} from './base';\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 */\nconst 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: 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 */\nexport 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\nexport class PieChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates the pie chart\n *\n * @param options\n */\n createChart(options) {\n var data = 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 = createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie);\n // Calculate charting rect\n chartRect = 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 = 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 + '-' + 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 = polarToCartesian(center.x, center.y, radius, overlappigStartAngle),\n end = 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 SvgPath(!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': 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 = 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 && !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","","export {version} from 'package.json!version';\n\n/**\n * This object contains all namespaces used within Chartist.\n *\n * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}}\n */\nexport let 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 * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number.\n *\n * @type {number}\n */\nexport let precision = 8;\n\n/**\n * A map with characters to escape for strings to be safely used as attribute values.\n *\n * @type {Object}\n */\nexport let escapingMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n '\\'': '''\n};\n","export default (function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n});","export default (function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n})();","import {Svg} from './svg';\n\n/**\n * This helper class is to wrap multiple `Svg` elements into a list where you can call the `Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Svg` on multiple elements.\n * An instance of this class is also returned by `Svg.querySelectorAll`.\n *\n * @memberof 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 */\nexport class SvgList {\n constructor(nodeList) {\n var list = this;\n\n this.svgElements = [];\n for(var i = 0; i < nodeList.length; i++) {\n this.svgElements.push(new Svg(nodeList[i]));\n }\n\n // Add delegation methods for Svg\n Object.keys(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 Svg.prototype[prototypeProperty].apply(element, args);\n });\n return list;\n };\n });\n }\n}\n","export class EventEmitter {\n constructor() {\n this.handlers = [];\n }\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 addEventHandler(event, handler) {\n this.handlers[event] = this.handlers[event] || [];\n this.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 removeEventHandler(event, handler) {\n // Only do something if there are event handlers with this name existing\n if(this.handlers[event]) {\n // If handler is set we will look for a specific handler and only remove this\n if(handler) {\n this.handlers[event].splice(this.handlers[event].indexOf(handler), 1);\n if(this.handlers[event].length === 0) {\n delete this.handlers[event];\n }\n } else {\n // If no handler is specified we remove all handlers for this event\n delete this.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 emit(event, data) {\n // Only do something if there are event handlers with this name existing\n if(this.handlers[event]) {\n this.handlers[event].forEach(function(handler) {\n handler(data);\n });\n }\n\n // Emit event to star event handlers\n if(this.handlers['*']) {\n this.handlers['*'].forEach(function(starHandler) {\n starHandler(event, data);\n });\n }\n }\n}\n","import {querySelector, extend, optionsProvider} from '../core/core';\nimport {EventEmitter} from '../event/event-emitter';\nimport {isSupported} from '../svg/svg';\n\nexport class BaseChart {\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 constructor(query, data, defaultOptions, options, responsiveOptions) {\n this.container = 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 = new EventEmitter();\n this.supportsForeignObject = isSupported('Extensibility');\n this.supportsAnimations = 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(this.initialize.bind(this), 0);\n }\n\n createChart() {\n throw new Error('Base chart type can\\'t be instantiated!');\n }\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 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 = 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 = 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 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 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 off(event, handler) {\n this.eventEmitter.removeEventHandler(event, handler);\n return this;\n }\n\n 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 = 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","export default (function (self, call) {\n if (!self) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\n});","export default (function (subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass);\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n});","import {isFalseyButZero} from '../core/lang';\nimport {createGrid, createLabel} from '../core/creation';\n\nexport const 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\nexport class Axis {\n initialize(units, chartRect, ticks, options) {\n this.units = units;\n this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x;\n this.options = options;\n this.chartRect = chartRect;\n this.axisLength = chartRect[this.units.rectEnd] - chartRect[this.units.rectStart];\n this.gridOffset = chartRect[this.units.rectOffset];\n this.ticks = ticks;\n }\n\n projectValue(value, index, data) {\n throw new Error('Base axis can\\'t be instantiated!');\n }\n\n 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(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 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 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","export default (function get(object, property, receiver) {\n if (object === null) object = Function.prototype;\n var desc = Object.getOwnPropertyDescriptor(object, property);\n\n if (desc === undefined) {\n var parent = Object.getPrototypeOf(object);\n\n if (parent === null) {\n return undefined;\n } else {\n return get(parent, property, receiver);\n }\n } else if (\"value\" in desc) {\n return desc.value;\n } else {\n var getter = desc.get;\n\n if (getter === undefined) {\n return undefined;\n }\n\n return getter.call(receiver);\n }\n});","import {getBounds, getHighLow, getMultiValue} from '../core/data';\nimport {Axis} from './axis';\n\nexport class AutoScaleAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\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 || getHighLow(data, options, axisUnit.pos);\n this.bounds = 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 super.initialize(axisUnit, chartRect, this.bounds.values, options);\n }\n\n projectValue(value) {\n return this.axisLength * (+getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range;\n }\n}\n","import {getMultiValue, getHighLow} from '../core/data';\nimport {times} from '../core/functional';\nimport {Axis} from './axis';\n\nexport class FixedScaleAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\n\n var highLow = options.highLow || getHighLow(data, options, axisUnit.pos);\n this.divisor = options.divisor || 1;\n this.ticks = options.ticks || 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 super.initialize(axisUnit, chartRect, this.ticks, options);\n\n this.stepLength = this.axisLength / this.divisor;\n }\n\n projectValue(value) {\n return this.axisLength * (+getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min);\n }\n}\n","import {Axis} from './axis';\n\nexport class StepAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\n super.initialize(axisUnit, chartRect, options.ticks, options);\n\n var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0));\n this.stepLength = this.axisLength / calc;\n }\n\n projectValue(value, index) {\n return this.stepLength * index;\n }\n}\n","import {isNumeric, alphaNumerate} from '../core/lang';\nimport {noop} from '../core/functional';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize, getMetaData, getSeriesOption} from '../core/data';\nimport {createSvg, createChartRect, createGridBackground} from '../core/creation';\nimport {StepAxis, AutoScaleAxis, axisUnits} from '../axes/axes';\nimport {BaseChart} from './base';\nimport {monotoneCubic, none} from '../interpolation/interpolation';\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 */\nconst 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: 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: 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\nexport class LineChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates a new chart\n *\n */\n createChart(options) {\n var data = normalizeData(this.data, options.reverseData, true);\n\n // Create new svg object\n this.svg = 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 = createChartRect(this.svg, options, defaultOptions.padding);\n var axisX, axisY;\n\n if(options.axisX.type === undefined) {\n axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n ticks: data.normalized.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, {\n high: isNumeric(options.high) ? options.high : options.axisY.high,\n low: isNumeric(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = new options.axisY.type(axisUnits.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 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': 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 + '-' + 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: getMetaData(series, valueIndex)\n });\n }.bind(this));\n\n var seriesOptions = {\n lineSmooth: getSeriesOption(series, options, 'lineSmooth'),\n showPoint: getSeriesOption(series, options, 'showPoint'),\n showLine: getSeriesOption(series, options, 'showLine'),\n showArea: getSeriesOption(series, options, 'showArea'),\n areaBase: getSeriesOption(series, options, 'areaBase')\n };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? monotoneCubic() : 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(isNumeric).join(','),\n 'ct:meta': 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","import {isNumeric, alphaNumerate} from '../core/lang';\nimport {noop, serialMap} from '../core/functional';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize, getMetaData, getHighLow} from '../core/data';\nimport {createSvg, createChartRect, createGridBackground} from '../core/creation';\nimport {AutoScaleAxis, StepAxis, axisUnits} from '../axes/axes';\nimport {BaseChart} from './base';\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 */\nconst 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: 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: 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\nexport class BarChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates a new chart\n *\n */\n createChart(options) {\n var data;\n var highLow;\n\n if(options.distributeSeries) {\n data = 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 = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n }\n\n // Create new svg element\n this.svg = 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 = 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 = getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y');\n\n } else {\n\n highLow = 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 = 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 AutoScaleAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n\n if(options.axisY.type === undefined) {\n labelAxis = axisY = new StepAxis(axisUnits.y, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisY = new options.axisY.type(axisUnits.units.y, data.normalized.series, chartRect, 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 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': 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 + '-' + 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 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 = 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(isNumeric).join(','),\n 'ct:meta': serialize(metaData)\n });\n\n this.eventEmitter.emit('draw', 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"]} \ No newline at end of file +{"version":3,"sources":["../src/core/lang.js","../src/core/math.js","../src/core/extend.js","../src/core/data.js","../src/svg/svg.js","../src/core/creation.js","../src/core/options-provider.js","../src/svg/svg-path.js","../src/interpolation/none.js","../src/interpolation/simple.js","../src/interpolation/step.js","../src/interpolation/cardinal.js","../src/interpolation/monotone-cubic.js","../src/charts/pie.js","../package.json!file:/home/gion/Code/chartist/tooling/system-loaders/package.json","../src/core/globals.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/toConsumableArray.js","../src/core/functional.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/classCallCheck.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/createClass.js","../src/svg/svg-list.js","../src/event/event-emitter.js","../src/charts/base.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/possibleConstructorReturn.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/inherits.js","../src/axes/axis.js","../jspm_packages/npm/systemjs-plugin-babel@0.0.16/babel-helpers/get.js","../src/axes/auto-scale-axis.js","../src/axes/fixed-scale-axis.js","../src/axes/step-axis.js","../src/charts/line.js","../src/charts/bar.js"],"names":["replaceAll","str","subStr","newSubStr","replace","RegExp","querySelector","query","Node","document","safeHasProperty","object","property","hasOwnProperty","isNumeric","value","isFinite","isFalseyButZero","getNumberOrUndefined","undefined","ensureUnit","unit","quantity","input","match","exec","alphaNumerate","n","String","fromCharCode","orderOfMagnitude","Math","floor","log","abs","LN10","projectLength","axisLength","length","bounds","range","roundWithPrecision","digits","precision","pow","globalPrecision","round","rho","num","gcd","p","q","f","x","x1","x2","divisor","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","extend","target","arguments","sources","Array","_len","_key","i","source","prop","sourceProp","serialize","data","JSON","stringify","Object","keys","escapingMap","reduce","result","key","deserialize","parse","e","normalizeData","reverse","multi","labelCount","output","normalized","series","getDataArray","every","max","apply","_toConsumableArray","map","labels","slice","push","_output$normalized$la","times","getMetaData","index","meta","isDataHoleValue","isNaN","reverseData","_step","Symbol","iterator","_iteratorNormalCompletion","_iterator","next","done","recursiveConvert","multiValue","y","isMultiValue","getMultiValue","dimension","getSeriesOption","options","name","seriesOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","segments","hole","fillHoles","increasingX","getHighLow","recursiveHighLow","sourceData","findHigh","highLow","high","findLow","low","toUpperCase","Number","MAX_VALUE","referenceValue","min","getBounds","scaleMinSpace","onlyInteger","safeIncrement","increment","EPSILON","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","optimizationCounter","Error","newMin","newMax","values","isSupported","feature","implementation","hasFeature","createSvg","container","width","height","className","from","querySelectorAll","filter","svg","getAttributeNS","namespaces","xmlns","forEach","removeChild","Svg","attr","addClass","appendChild","_node","normalizePadding","padding","fallback","top","right","bottom","left","createChartRect","fallbackPadding","hasAxis","axisX","axisY","yAxisOffset","offset","xAxisOffset","normalizedPadding","chartPadding","chartRect","this","y1","y2","position","createGrid","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","stepLength","stepCounterLength","content","trim","foreignObject","text","optionsProvider","responsiveOptions","updateCurrentOptions","mediaEvent","previousOptions","currentOptions","baseOptions","responsiveOption","mql","window","matchMedia","matches","removeMediaQueryListeners","removeListener","mediaQueryListeners","addListener","element","command","params","pathElements","relative","pathElement","toLowerCase","splice","forEachParam","cb","pathElementIndex","paramName","paramIndex","none","path","SvgPath","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","postpone","cardinal","t","tension","c","cardinalInterpolation","segment","z","iLen","monotoneCubic","monotoneCubicInterpolation","xs","ys","ms","ds","dys","dxs","determineAnchorPosition","center","label","direction","toTheRight","version","arr","isArray","arr2","noop","sum","previous","current","serialMap","array","callback","inner","_classCallCheck","instance","Constructor","TypeError","_createClass","defineProperties","props","descriptor","enumerable","configurable","writable","defineProperty","protoProps","staticProps","prototype","SvgList","nodeList","list","svgElements","prototypeProperty","indexOf","args","_arguments","attributes","parent","insertFirst","Element","createElementNS","ct","firstChild","insertBefore","ns","getAttribute","namespacedAttribute","split","setAttributeNS","setAttribute","bind","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","createElement","innerHTML","fnObj","createTextNode","newElement","replaceChild","names","concat","self","removedClasses","getBoundingClientRect","animations","guided","attribute","createAnimate","animationDefinition","createGuided","attributeProperties","animationEasing","timeout","easing","easings","begin","dur","calcMode","keySplines","keyTimes","fill","animate","_this","beginElement","err","to","remove","addEventListener","EventEmitter","handlers","event","handler","starHandler","BaseChart","supportsForeignObject","supportsAnimations","resizeListener","update","__chartist__","detach","initializeTimeoutId","setTimeout","initialize","override","createChart","getCurrentOptions","clearTimeout","removeEventListener","addEventHandler","removeEventHandler","_this2","plugins","plugin","_possibleConstructorReturn","call","ReferenceError","_inherits","subClass","superClass","create","setPrototypeOf","__proto__","axisUnits","Axis","ticks","rectEnd","rectStart","gridOffset","rectOffset","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","end","_get","get","receiver","Function","desc","getOwnPropertyDescriptor","getPrototypeOf","getter","AutoScaleAxis","_Axis","axisUnit","FixedScaleAxis","sort","a","b","StepAxis","calc","stretch","elementDescriptions","close","paths","joinedPath","j","count","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","_pathElements","accuracyMultiplier","accuracy","transformFnc","transformed","clone","LineChart","_BaseChart","chart","seriesGroup","type","fullWidth","createGridAndLabels","showGridBackground","raw","seriesIndex","seriesElement","pathData","valueIndex","smoothing","lineSmooth","showPoint","point","showLine","showArea","areaBase","areaBaseProjected","splitByCommand","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","BarChart","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","biPol","periodHalfLength","labelAxisValueIndex","projected","seriesBarDistance","previousStack","positions","stackMode","metaData","bar","PieChart","seriesGroups","labelsGroup","labelRadius","startAngle","donut","chartDonut","chartPie","totalDataSum","total","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","start","arc","sliceDonut","slicePie","rawValue","interpolatedValue","labelDirection"],"mappings":"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","file":"chartist.umd.js","sourcesContent":["/**\n * Replaces all occurrences of subStr in str with newSubStr and returns a new string.\n *\n * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @return {String}\n */\nexport function replaceAll(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\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 */\nexport function querySelector(query) {\n return query instanceof Node ? query : document.querySelector(query);\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 */\nexport function safeHasProperty(object, property) {\n return object !== null &&\n typeof object === 'object' &&\n object.hasOwnProperty(property);\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 */\nexport function isNumeric(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 */\nexport function isFalseyButZero(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 */\nexport function getNumberOrUndefined(value) {\n return isNumeric(value) ? +value : undefined;\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 */\nexport function ensureUnit(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 */\nexport function quantity(input) {\n if(typeof input === 'string') {\n const match = (/^(\\d+)\\s*(.*)$/g).exec(input);\n return {\n value: +match[1],\n unit: match[2] || undefined\n };\n }\n\n return {\n value: input\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 */\nexport function alphaNumerate(n) {\n // Limit to a-z\n return String.fromCharCode(97 + n % 26);\n}\n","import {precision as globalPrecision} from './globals';\n\nexport const EPSILON = 2.221E-16;\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 */\nexport function orderOfMagnitude(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 */\nexport function projectLength(axisLength, length, bounds) {\n return length / bounds.range * axisLength;\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 */\nexport function roundWithPrecision(value, digits) {\n const precision = Math.pow(10, digits || globalPrecision);\n return Math.round(value * precision) / precision;\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 */\nexport function rho(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 let x1 = 2;\n let x2 = 2;\n let 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 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 */\nexport function polarToCartesian(centerX, centerY, radius, angleInDegrees) {\n const 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 * 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 */\nexport function extend(target = {}, ...sources) {\n target = target || {};\n\n for(let i = 0; i < sources.length; i++) {\n const source = sources[i];\n for(let prop in source) {\n const sourceProp = source[prop];\n if(typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) {\n target[prop] = extend(target[prop], sourceProp);\n } else {\n target[prop] = sourceProp;\n }\n }\n }\n\n return target;\n}\n","import {escapingMap} from './globals';\nimport {replaceAll, safeHasProperty, getNumberOrUndefined} from './lang';\nimport {times} from './functional';\nimport {extend} from './extend';\nimport {orderOfMagnitude, projectLength, roundWithPrecision, rho, EPSILON} from './math';\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 */\nexport function serialize(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(escapingMap)\n .reduce((result, key) => replaceAll(result, key, escapingMap[key]), 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 */\nexport function deserialize(data) {\n if(typeof data !== 'string') {\n return data;\n }\n\n data = Object.keys(escapingMap)\n .reduce((result, key) => replaceAll(result, escapingMap[key], key), data);\n\n try {\n data = JSON.parse(data);\n data = data.data !== undefined ? data.data : data;\n } catch(e) {\n }\n\n return data;\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 */\nexport function normalizeData(data, reverse, multi) {\n let labelCount;\n const 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 = 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((value) => value instanceof Array)) {\n // Getting the series with the the most elements\n labelCount = Math.max(...output.normalized.series.map((series) => series.length));\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 output.normalized.labels\n .push(...times(Math.max(0, labelCount - output.normalized.labels.length))\n .map(() => ''));\n\n if(reverse) {\n reverseData(output.normalized);\n }\n\n return output;\n}\n\n/**\n * Get meta data of a specific value in a series.\n *\n * @param series\n * @param index\n * @returns {*}\n */\nexport function getMetaData(series, index) {\n const value = series.data ? series.data[index] : series[index];\n return value ? value.meta : undefined;\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 */\nexport function isDataHoleValue(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 */\nexport function reverseData(data) {\n data.labels.reverse();\n data.series.reverse();\n for(let series of data.series) {\n if(typeof(series) === 'object' && series.data !== undefined) {\n series.data.reverse();\n } else if(series instanceof Array) {\n series.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 */\nexport function getDataArray(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(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(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(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 const 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] = getNumberOrUndefined(value);\n } else {\n multiValue.y = getNumberOrUndefined(value);\n }\n\n multiValue.x = value.hasOwnProperty('x') ? getNumberOrUndefined(value.x) : multiValue.x;\n multiValue.y = value.hasOwnProperty('y') ? getNumberOrUndefined(value.y) : multiValue.y;\n\n return multiValue;\n\n } else {\n // We can return simple data\n return getNumberOrUndefined(value);\n }\n }\n }\n\n return data.series.map(recursiveConvert);\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 */\nexport function isMultiValue(value) {\n return typeof value === 'object' &&\n (value.hasOwnProperty('x') || value.hasOwnProperty('y'));\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 * @returns {*}\n */\nexport function getMultiValue(value, dimension = 'y') {\n if(isMultiValue(value)) {\n return getNumberOrUndefined(value[dimension]);\n } else {\n return getNumberOrUndefined(value);\n }\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 */\nexport function getSeriesOption(series, options, key) {\n if(series.name && options.series && options.series[series.name]) {\n const 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 * 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} valueData 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 */\nexport function splitIntoSegments(pathCoordinates, valueData, options) {\n const defaultOptions = {\n increasingX: false,\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n const segments = [];\n let hole = true;\n\n for(let i = 0; i < pathCoordinates.length; i += 2) {\n // If this value is a \"hole\" we set the hole flag\n if(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\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 */\nexport function getHighLow(data, options, dimension) {\n // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred\n options = extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {});\n\n const highLow = {\n high: options.high === undefined ? -Number.MAX_VALUE : +options.high,\n low: options.low === undefined ? Number.MAX_VALUE : +options.low\n };\n const findHigh = options.high === undefined;\n const findLow = options.low === undefined;\n\n // Function to recursively walk through arrays and find highest and lowest number\n function recursiveHighLow(sourceData) {\n if(sourceData === undefined) {\n return undefined;\n } else if(sourceData instanceof Array) {\n for(let i = 0; i < sourceData.length; i++) {\n recursiveHighLow(sourceData[i]);\n }\n } else {\n const value = dimension ? +sourceData[dimension] : +sourceData;\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 * 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 */\nexport function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) {\n const bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = 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 const length = projectLength(axisLength, bounds.step, bounds);\n const scaleUp = length < scaleMinSpace;\n const smallestFactor = onlyInteger ? 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 && projectLength(axisLength, 1, bounds) >= scaleMinSpace) {\n bounds.step = 1;\n } else if(onlyInteger && smallestFactor < bounds.step && 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 let optimizationCounter = 0;\n while(true) {\n if(scaleUp && projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) {\n bounds.step *= 2;\n } else if(!scaleUp && 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 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 value *= (1 + (increment > 0 ? EPSILON : -EPSILON));\n }\n return value;\n }\n\n // Narrow min and max based on new step\n let newMin = bounds.min;\n let newMax = bounds.max;\n while(newMin + bounds.step <= bounds.low) {\n newMin = safeIncrement(newMin, bounds.step);\n }\n while(newMax - bounds.step >= bounds.high) {\n newMax = safeIncrement(newMax, -bounds.step);\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n const values = [];\n for(let i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) {\n const value = roundWithPrecision(i);\n if(value !== values[values.length - 1]) {\n values.push(value);\n }\n }\n bounds.values = values;\n\n return bounds;\n}\n","import {namespaces, ensureUnit, quantity, extend} from '../core/core';\nimport {SvgList} from './svg-list';\n\n/**\n * 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 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 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 */\nexport class Svg {\n\n constructor(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(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': 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 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 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 const namespacedAttribute = key.split(':');\n this._node.setAttributeNS(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 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 {Svg} Returns a Svg wrapper object that can be used to modify the containing SVG data\n */\n elem(name, attributes, className, insertFirst) {\n return new Svg(name, attributes, className, this, insertFirst);\n }\n\n /**\n * Returns the parent Chartist.SVG wrapper object\n *\n * @memberof Svg\n * @return {Svg} Returns a 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 parent() {\n return this._node.parentNode instanceof SVGElement ? new Svg(this._node.parentNode) : null;\n }\n\n /**\n * This method returns a Svg wrapper around the root SVG element of the current tree.\n *\n * @memberof Svg\n * @return {Svg} The root SVG element wrapped in a Svg element\n */\n root() {\n let node = this._node;\n while(node.nodeName !== 'svg') {\n node = node.parentNode;\n }\n return new 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 Svg wrapper.\n *\n * @memberof Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {Svg} The SVG wrapper for the element found or null if no element was found\n */\n querySelector(selector) {\n const foundNode = this._node.querySelector(selector);\n return foundNode ? new 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 Svg.List wrapper.\n *\n * @memberof Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {SvgList} The SVG wrapper list for the element found or null if no element was found\n */\n querySelectorAll(selector) {\n const foundNodes = this._node.querySelectorAll(selector);\n return foundNodes.length ? new SvgList(foundNodes) : null;\n }\n\n /**\n * Returns the underlying SVG node for the current element.\n *\n * @memberof Svg\n * @returns {Node}\n */\n 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 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 {Svg} New wrapper object that wraps the foreignObject element\n */\n 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 const container = document.createElement('div');\n container.innerHTML = content;\n content = container.firstChild;\n }\n\n // Adding namespace to content element\n content.setAttribute('xmlns', 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 const 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 Svg wrapper.\n *\n * @memberof Svg\n * @param {String} t The text that should be added to the text element that is created\n * @return {Svg} The same wrapper object that was used to add the newly created element\n */\n 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 Svg\n * @return {Svg} The same wrapper object that got emptied\n */\n 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 Svg\n * @return {Svg} The parent wrapper object of the element that got removed\n */\n 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 Svg\n * @param {Svg} newElement The new Svg object that will be used to replace the current wrapper object\n * @return {Svg} The wrapper of the new element\n */\n 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 Svg\n * @param {Svg} element The 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 {Svg} The wrapper of the appended object\n */\n 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 Svg\n * @return {Array} A list of classes or an empty array if there are no classes on the current element\n */\n 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 Svg\n * @param {String} names A white space separated list of class names\n * @return {Svg} The wrapper of the current element\n */\n addClass(names) {\n this._node.setAttribute('class',\n this.classes()\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 Svg\n * @param {String} names A white space separated list of class names\n * @return {Svg} The wrapper of the current element\n */\n removeClass(names) {\n const removedClasses = names.trim().split(/\\s+/);\n\n this._node.setAttribute('class',\n this.classes().filter((name) => removedClasses.indexOf(name) === -1).join(' '));\n\n return this;\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Svg\n * @return {Svg} The wrapper of the current element\n */\n removeAllClasses() {\n this._node.setAttribute('class', '');\n return this;\n }\n\n /**\n * Get element height using `getBoundingClientRect`\n *\n * @memberof Svg\n * @return {Number} The elements height in pixels\n */\n 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 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 `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 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 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 {Svg} The current element where the animation was added\n */\n animate(animations, guided, eventEmitter) {\n if(guided === undefined) {\n guided = true;\n }\n\n Object.keys(animations).forEach((attribute) => {\n\n const createAnimate = (animationDefinition, createGuided) => {\n const attributeProperties = {};\n let animationEasing;\n let timeout;\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 animationEasing = animationDefinition.easing instanceof Array ?\n animationDefinition.easing :\n easings[animationDefinition.easing];\n delete animationDefinition.easing;\n }\n\n // If numeric dur or begin was provided we assume milli seconds\n animationDefinition.begin = ensureUnit(animationDefinition.begin, 'ms');\n animationDefinition.dur = ensureUnit(animationDefinition.dur, 'ms');\n\n if(animationEasing) {\n animationDefinition.calcMode = 'spline';\n animationDefinition.keySplines = animationEasing.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(createGuided) {\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 = quantity(animationDefinition.begin || 0).value;\n animationDefinition.begin = 'indefinite';\n }\n\n const animate = this.elem('animate', extend({\n attributeName: attribute\n }, animationDefinition));\n\n if(createGuided) {\n // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout\n setTimeout(() => {\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 occurred 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 }, timeout);\n }\n\n if(eventEmitter) {\n animate._node.addEventListener('beginEvent', () =>\n eventEmitter.emit('animationBegin', {\n element: this,\n animate: animate._node,\n params: animationDefinition\n })\n );\n }\n\n animate._node.addEventListener('endEvent', () => {\n if(eventEmitter) {\n eventEmitter.emit('animationEnd', {\n element: this,\n animate: animate._node,\n params: animationDefinition\n });\n }\n\n if(createGuided) {\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 });\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]\n .forEach((animationDefinition) => createAnimate(animationDefinition, false));\n } else {\n createAnimate(animations[attribute], guided);\n }\n });\n\n return this;\n }\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 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 */\nexport function isSupported(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 `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 Svg\n */\nexport const easings = {\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","import {namespaces} from './globals';\nimport {Svg} from '../svg/svg';\nimport {quantity} from './lang';\nimport {extend} from './extend';\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 */\nexport function createSvg(container, width = '100%', height = '100%', className) {\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.from(container.querySelectorAll('svg'))\n .filter((svg) => svg.getAttributeNS(namespaces.xmlns, 'ct'))\n .forEach((svg) => container.removeChild(svg));\n\n // Create svg object with width and height or use 100% as default\n const svg = new Svg('svg').attr({\n width,\n height\n }).addClass(className).attr({\n // TODO: Check better solution (browser support) and remove inline styles due to CSP\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 * 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 */\nexport function normalizePadding(padding, fallback = 0) {\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/**\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 */\nexport function createChartRect(svg, options, fallbackPadding) {\n const hasAxis = !!(options.axisX || options.axisY);\n const yAxisOffset = hasAxis ? options.axisY.offset : 0;\n const 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 let width = svg.width() || quantity(options.width).value || 0;\n let height = svg.height() || quantity(options.height).value || 0;\n const normalizedPadding = 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 const 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 */\nexport function createGrid(position, index, axis, offset, length, group, classes, eventEmitter) {\n const 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 const gridElement = group.elem('line', positionalData, classes.join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw',\n extend({\n type: 'grid',\n axis,\n index,\n 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 */\nexport function createGridBackground(gridGroup, chartRect, className, eventEmitter) {\n const 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 */\nexport function createLabel(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n let labelElement;\n const 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 const stepLength = Math.round(positionalData[axis.units.len]);\n const stepCounterLength = Math.round(positionalData[axis.counterUnits.len]);\n const content = `\n \n ${labels[index]}\n \n `.trim();\n\n labelElement = group.foreignObject(content, 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', extend({\n type: 'label',\n axis,\n index,\n group,\n element: labelElement,\n text: labels[index]\n }, positionalData));\n}\n","import {extend} from './extend';\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 */\nexport function optionsProvider(options, responsiveOptions, eventEmitter) {\n const baseOptions = extend({}, options);\n let currentOptions;\n const mediaQueryListeners = [];\n\n function updateCurrentOptions(mediaEvent) {\n const previousOptions = currentOptions;\n currentOptions = extend({}, baseOptions);\n\n if(responsiveOptions) {\n responsiveOptions.forEach((responsiveOption) => {\n const mql = window.matchMedia(responsiveOption[0]);\n if(mql.matches) {\n currentOptions = extend(currentOptions, responsiveOption[1]);\n }\n });\n }\n\n if(eventEmitter && mediaEvent) {\n eventEmitter.emit('optionsChanged', {\n previousOptions,\n currentOptions\n });\n }\n }\n\n function removeMediaQueryListeners() {\n mediaQueryListeners.forEach((mql) => mql.removeListener(updateCurrentOptions));\n }\n\n if(!window.matchMedia) {\n throw 'window.matchMedia not found! Make sure you\\'re using a polyfill.';\n } else if(responsiveOptions) {\n responsiveOptions.forEach((responsiveOption) => {\n const mql = window.matchMedia(responsiveOption[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,\n getCurrentOptions() {\n return extend({}, currentOptions);\n }\n };\n}\n","import {extend} from '../core/core';\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 SvgPath\n * @type {Object}\n */\nconst 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 SvgPath\n * @type {Object}\n */\nconst 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\nfunction element(command, params, pathElements, pos, relative, data) {\n const pathElement = extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params, data ? {data: data} : {});\n\n pathElements.splice(pos, 0, pathElement);\n}\n\nfunction forEachParam(pathElements, cb) {\n pathElements.forEach((pathElement, pathElementIndex) => {\n elementDescriptions[pathElement.command.toLowerCase()].forEach((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 SvgPath\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 */\nexport class SvgPath {\n /**\n * This static function on `SvgPath` is joining multiple paths together into one paths.\n *\n * @memberof SvgPath\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 {SvgPath}\n */\n static join(paths, close, options) {\n const joinedPath = new SvgPath(close, options);\n for(let i = 0; i < paths.length; i++) {\n const path = paths[i];\n for(let j = 0; j < path.pathElements.length; j++) {\n joinedPath.pathElements.push(path.pathElements[j]);\n }\n }\n return joinedPath;\n }\n\n constructor(close, options) {\n this.pathElements = [];\n this.pos = 0;\n this.close = close;\n this.options = 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 SvgPath\n * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array.\n * @return {SvgPath|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 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 SvgPath\n * @param {Number} count Number of path elements that should be removed from the current position.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n 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 SvgPath\n * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n parse(path) {\n // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']]\n const 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((result, pathElement) => {\n if(pathElement.match(/[A-Za-z]/)) {\n result.push([]);\n }\n\n result[result.length - 1].push(pathElement);\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 const elements = chunks.map((chunk) => {\n const command = chunk.shift();\n const description = elementDescriptions[command.toLowerCase()];\n\n return extend({\n command: command\n }, description.reduce((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 this.pathElements.splice(this.pos, 0, ...elements);\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 SvgPath\n * @return {String}\n */\n stringify() {\n const accuracyMultiplier = Math.pow(10, this.options.accuracy);\n\n return this.pathElements.reduce((path, pathElement) => {\n const params = elementDescriptions[pathElement.command.toLowerCase()].map((paramName) =>\n this.options.accuracy ?\n (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) :\n pathElement[paramName]\n );\n\n return path + pathElement.command + params.join(',');\n }, '') + (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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n scale(x, y) {\n forEachParam(this.pathElements, (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 SvgPath\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 {SvgPath} The current path object for easy call chaining.\n */\n translate(x, y) {\n forEachParam(this.pathElements, (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 SvgPath\n * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description.\n * @return {SvgPath} The current path object for easy call chaining.\n */\n transform(transformFnc) {\n forEachParam(this.pathElements, (pathElement, paramName, pathElementIndex, paramIndex, pathElements) => {\n const 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 SvgPath\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 {SvgPath}\n */\n clone(close) {\n const clone = new SvgPath(close || this.close);\n clone.pos = this.pos;\n clone.pathElements = this.pathElements.slice().map((pathElement) => extend({}, pathElement));\n clone.options = extend({}, this.options);\n return clone;\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 SvgPath\n * @param {String} command The command you'd like to use to split the path\n * @return {Array}\n */\n splitByCommand(command) {\n const split = [\n new SvgPath()\n ];\n\n this.pathElements.forEach((pathElement) => {\n if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) {\n split.push(new SvgPath());\n }\n\n split[split.length - 1].pathElements.push(pathElement);\n });\n\n return split;\n }\n}\n","import {extend, getMultiValue} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function none(options) {\n const defaultOptions = {\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n return function noneInterpolation(pathCoordinates, valueData) {\n const path = new SvgPath();\n let hole = true;\n\n for(let i = 0; i < pathCoordinates.length; i += 2) {\n const currX = pathCoordinates[i];\n const currY = pathCoordinates[i + 1];\n const currData = valueData[i / 2];\n\n if(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","import {extend} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function simple(options) {\n const defaultOptions = {\n divisor: 2,\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n const d = 1 / Math.max(1, options.divisor);\n\n return function simpleInterpolation(pathCoordinates, valueData) {\n const path = new SvgPath();\n let prevX;\n let prevY;\n let prevData;\n\n for(let i = 0; i < pathCoordinates.length; i += 2) {\n const currX = pathCoordinates[i];\n const currY = pathCoordinates[i + 1];\n const length = (currX - prevX) * d;\n const 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 = prevY = prevData = undefined;\n }\n }\n\n return path;\n };\n}\n","import {extend} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\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 */\nexport function step(options) {\n const defaultOptions = {\n postpone: true,\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n return function stepInterpolation(pathCoordinates, valueData) {\n const path = new SvgPath();\n\n let prevX;\n let prevY;\n let prevData;\n\n for(let i = 0; i < pathCoordinates.length; i += 2) {\n const currX = pathCoordinates[i];\n const currY = pathCoordinates[i + 1];\n const 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","import {extend, splitIntoSegments} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\nimport {none} from './none';\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 */\nexport function cardinal(options) {\n const defaultOptions = {\n tension: 1,\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n const t = Math.min(1, Math.max(0, options.tension));\n const c = 1 - t;\n\n return function cardinalInterpolation(pathCoordinates, valueData) {\n // First we try to split the coordinates into segments\n // This is necessary to treat \"holes\" in line charts\n const segments = splitIntoSegments(pathCoordinates, valueData, {\n fillHoles: options.fillHoles\n });\n\n if(!segments.length) {\n // If there were no segments return 'none' interpolation\n return 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 // For each segment we will recurse the cardinal function\n // Join the segment path data into a single path and return\n return SvgPath.join(\n segments.map((segment) => cardinalInterpolation(segment.pathCoordinates, segment.valueData))\n );\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 none()(pathCoordinates, valueData);\n }\n\n const path = new SvgPath().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]);\n let z;\n\n for(let i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) {\n const 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\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","import {extend, splitIntoSegments} from '../core/core';\nimport {SvgPath} from '../svg/svg-path';\nimport {none} from './none';\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 */\nexport function monotoneCubic(options) {\n const defaultOptions = {\n fillHoles: false\n };\n\n options = extend({}, defaultOptions, options);\n\n return function monotoneCubicInterpolation(pathCoordinates, valueData) {\n // First we try to split the coordinates into segments\n // This is necessary to treat \"holes\" in line charts\n const segments = 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 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 // For each segment we will recurse the monotoneCubic fn function\n // Join the segment path data into a single path and return\n return SvgPath.join(\n segments.map((segment) => monotoneCubicInterpolation(segment.pathCoordinates, segment.valueData))\n );\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 none()(pathCoordinates, valueData);\n }\n\n const xs = [];\n const ys = [];\n const n = pathCoordinates.length / 2;\n const ms = [];\n const ds = [];\n const dys = [];\n const dxs = [];\n\n // Populate x and y coordinates into separate arrays, for readability\n for(let 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 for(let 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 ms[0] = ds[0];\n ms[n - 1] = ds[n - 2];\n\n for(let 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 const path = new SvgPath().move(xs[0], ys[0], false, valueData[0]);\n\n for(let 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","import {alphaNumerate, quantity, isFalseyButZero} from '../core/lang';\nimport {noop, sum} from '../core/functional';\nimport {polarToCartesian} from '../core/math';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize} from '../core/data';\nimport {createSvg, createChartRect} from '../core/creation';\nimport {SvgPath} from '../svg/svg-path';\nimport {BaseChart} from './base';\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 */\nconst 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: 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 */\nexport function determineAnchorPosition(center, label, direction) {\n const 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\nexport class PieChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates the pie chart\n *\n * @param options\n */\n createChart(options) {\n const data = normalizeData(this.data);\n const seriesGroups = [];\n let labelsGroup;\n let labelRadius;\n let startAngle = options.startAngle;\n\n // Create SVG.js draw\n this.svg = createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie);\n // Calculate charting rect\n const chartRect = createChartRect(this.svg, options, defaultOptions.padding);\n // Get biggest circle radius possible within chartRect\n let 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 const totalDataSum = options.total ||\n data.normalized.series.reduce(sum, 0);\n\n const donutWidth = 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 const 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 const hasSingleValInSeries = data.raw.series\n .filter((val) => val.hasOwnProperty('value') ? val.value !== 0 : val !== 0)\n .length === 1;\n\n // Creating the series groups\n data.raw.series\n .forEach((series, index) => seriesGroups[index] = this.svg.elem('g', null, null));\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((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) {\n return;\n }\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}-${alphaNumerate(index)}`\n ].join(' '));\n\n // If the whole dataset is 0 endAngle should be zero. Can't divide by 0.\n let endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0);\n\n // Use slight offset so there are no transparent hairline issues\n const 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 const start = polarToCartesian(center.x, center.y, radius, overlappigStartAngle);\n const end = 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 const path = new SvgPath(!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 const 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': 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 let labelPosition;\n\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 = polarToCartesian(\n center.x,\n center.y,\n labelRadius,\n startAngle + (endAngle - startAngle) / 2\n );\n }\n\n let rawValue;\n if(data.normalized.labels && !isFalseyButZero(data.normalized.labels[index])) {\n rawValue = data.normalized.labels[index];\n } else {\n rawValue = data.normalized.series[index];\n }\n\n const interpolatedValue = options.labelInterpolationFnc(rawValue, index);\n\n if(interpolatedValue || interpolatedValue === 0) {\n const 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,\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 });\n\n this.eventEmitter.emit('created', {\n chartRect,\n svg: this.svg,\n options\n });\n }\n}\n","","export {version} from 'package.json!version';\n\n/**\n * This object contains all namespaces used within Chartist.\n *\n * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}}\n */\nexport let 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 * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number.\n *\n * @type {number}\n */\nexport let precision = 8;\n\n/**\n * A map with characters to escape for strings to be safely used as attribute values.\n *\n * @type {Object}\n */\nexport let escapingMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n '\\'': '''\n};\n","export default (function (arr) {\n if (Array.isArray(arr)) {\n for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];\n\n return arr2;\n } else {\n return Array.from(arr);\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 */\nexport const noop = (n) => 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 */\nexport const times = (length) => Array.from({length});\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 */\nexport const sum = (previous, current) => previous + (current ? current : 0);\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 * For example:\n * @example\n * ```javascript\n * const data = [[1, 2], [3], []];\n * serialMap(data, cb);\n *\n * // where cb will be called 2 times\n * // 1. call arguments: (1, 3, undefined)\n * // 2. call arguments: (2, undefined, undefined)\n * ```\n *\n * @memberof Chartist.Core\n * @param array\n * @param callback\n * @return {Array}\n */\nexport const serialMap = (array, callback) =>\n times(Math.max(...array.map((element) => element.length)))\n .map((inner, index) => callback(...array.map((element) => element[index])));\n","export default (function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n});","export default (function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n})();","import {Svg} from './svg';\n\n/**\n * This helper class is to wrap multiple `Svg` elements into a list where you can call the `Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Svg` on multiple elements.\n * An instance of this class is also returned by `Svg.querySelectorAll`.\n *\n * @memberof 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 */\nexport class SvgList {\n constructor(nodeList) {\n const list = this;\n\n this.svgElements = [];\n for(let i = 0; i < nodeList.length; i++) {\n this.svgElements.push(new Svg(nodeList[i]));\n }\n\n // Add delegation methods for Svg\n Object.keys(Svg.prototype).filter((prototypeProperty) => [\n 'constructor',\n 'parent',\n 'querySelector',\n 'querySelectorAll',\n 'replace',\n 'append',\n 'classes',\n 'height',\n 'width'\n ].indexOf(prototypeProperty) === -1)\n .forEach((prototypeProperty) => {\n list[prototypeProperty] = () => {\n const args = Array.from(arguments);\n list.svgElements.forEach((element) =>\n Svg.prototype[prototypeProperty].apply(element, args));\n return list;\n };\n });\n }\n}\n","export class EventEmitter {\n constructor() {\n this.handlers = [];\n }\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 addEventHandler(event, handler) {\n this.handlers[event] = this.handlers[event] || [];\n this.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 removeEventHandler(event, handler) {\n // Only do something if there are event handlers with this name existing\n if(this.handlers[event]) {\n // If handler is set we will look for a specific handler and only remove this\n if(handler) {\n this.handlers[event].splice(this.handlers[event].indexOf(handler), 1);\n if(this.handlers[event].length === 0) {\n delete this.handlers[event];\n }\n } else {\n // If no handler is specified we remove all handlers for this event\n delete this.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 emit(event, data) {\n // Only do something if there are event handlers with this name existing\n if(this.handlers[event]) {\n this.handlers[event].forEach((handler) => handler(data));\n }\n\n // Emit event to star event handlers\n if(this.handlers['*']) {\n this.handlers['*'].forEach((starHandler) => starHandler(event, data));\n }\n }\n}\n","import {querySelector, extend, optionsProvider} from '../core/core';\nimport {EventEmitter} from '../event/event-emitter';\nimport {isSupported} from '../svg/svg';\n\nexport class BaseChart {\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 constructor(query, data, defaultOptions, options, responsiveOptions) {\n this.container = 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 = new EventEmitter();\n this.supportsForeignObject = isSupported('Extensibility');\n this.supportsAnimations = isSupported('AnimationEventsAttribute');\n this.resizeListener = () => this.update();\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(() => this.initialize(), 0);\n }\n\n createChart() {\n throw new Error('Base chart type can\\'t be instantiated!');\n }\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 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 = 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 = 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 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 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 off(event, handler) {\n this.eventEmitter.removeEventHandler(event, handler);\n return this;\n }\n\n 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 = optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n // Register options change listener that will trigger a chart update\n this.eventEmitter.addEventHandler('optionsChanged', () => this.update());\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((plugin) => {\n if(plugin instanceof Array) {\n plugin[0](this, plugin[1]);\n } else {\n plugin(this);\n }\n });\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","export default (function (self, call) {\n if (!self) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\n});","export default (function (subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass);\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n});","import {isFalseyButZero} from '../core/lang';\nimport {createGrid, createLabel} from '../core/creation';\n\nexport const 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\nexport class Axis {\n initialize(units, chartRect, ticks, options) {\n this.units = units;\n this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x;\n this.options = options;\n this.chartRect = chartRect;\n this.axisLength = chartRect[this.units.rectEnd] - chartRect[this.units.rectStart];\n this.gridOffset = chartRect[this.units.rectOffset];\n this.ticks = ticks;\n }\n\n projectValue(value, index, data) {\n throw new Error('Base axis can\\'t be instantiated!');\n }\n\n createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) {\n const axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()];\n const projectedValues = this.ticks.map(this.projectValue.bind(this));\n const labelValues = this.ticks.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach((projectedValue, index) => {\n const 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 let 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 (except for 0)\n if(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 +\n chartOptions.axisX.labelOffset.y +\n (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = this.chartRect.y1 +\n chartOptions.axisX.labelOffset.y +\n (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 ?\n this.chartRect.padding.left + chartOptions.axisY.labelOffset.x :\n 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 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 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 });\n }\n}\n","export default (function get(object, property, receiver) {\n if (object === null) object = Function.prototype;\n var desc = Object.getOwnPropertyDescriptor(object, property);\n\n if (desc === undefined) {\n var parent = Object.getPrototypeOf(object);\n\n if (parent === null) {\n return undefined;\n } else {\n return get(parent, property, receiver);\n }\n } else if (\"value\" in desc) {\n return desc.value;\n } else {\n var getter = desc.get;\n\n if (getter === undefined) {\n return undefined;\n }\n\n return getter.call(receiver);\n }\n});","import {getBounds, getHighLow, getMultiValue} from '../core/data';\nimport {Axis} from './axis';\n\nexport class AutoScaleAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\n // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options\n const highLow = options.highLow || getHighLow(data, options, axisUnit.pos);\n this.bounds = 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 super.initialize(axisUnit, chartRect, this.bounds.values, options);\n }\n\n projectValue(value) {\n return this.axisLength * (+getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range;\n }\n}\n","import {getMultiValue, getHighLow} from '../core/data';\nimport {times} from '../core/functional';\nimport {Axis} from './axis';\n\nexport class FixedScaleAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\n\n const highLow = options.highLow || getHighLow(data, options, axisUnit.pos);\n this.divisor = options.divisor || 1;\n this.ticks = options.ticks ||\n times(this.divisor).map(\n (value, index) => highLow.low + (highLow.high - highLow.low) / this.divisor * index\n );\n this.ticks.sort((a, b) => a - b);\n this.range = {\n min: highLow.low,\n max: highLow.high\n };\n\n super.initialize(axisUnit, chartRect, this.ticks, options);\n\n this.stepLength = this.axisLength / this.divisor;\n }\n\n projectValue(value) {\n return this.axisLength * (+getMultiValue(value, this.units.pos) - this.range.min) /\n (this.range.max - this.range.min);\n }\n}\n","import {Axis} from './axis';\n\nexport class StepAxis extends Axis {\n constructor(axisUnit, data, chartRect, options) {\n super();\n super.initialize(axisUnit, chartRect, options.ticks, options);\n\n const calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0));\n this.stepLength = this.axisLength / calc;\n }\n\n projectValue(value, index) {\n return this.stepLength * index;\n }\n}\n","import {isNumeric, alphaNumerate} from '../core/lang';\nimport {noop} from '../core/functional';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize, getMetaData, getSeriesOption} from '../core/data';\nimport {createSvg, createChartRect, createGridBackground} from '../core/creation';\nimport {StepAxis, AutoScaleAxis, axisUnits} from '../axes/axes';\nimport {BaseChart} from './base';\nimport {monotoneCubic, none} from '../interpolation/interpolation';\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 */\nconst 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: 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: 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\nexport class LineChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates a new chart\n *\n */\n createChart(options) {\n const data = normalizeData(this.data, options.reverseData, true);\n\n // Create new svg object\n this.svg = createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Create groups for labels, grid and series\n const gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n const seriesGroup = this.svg.elem('g');\n const labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);\n\n const chartRect = createChartRect(this.svg, options, defaultOptions.padding);\n let axisX;\n let axisY;\n\n if(options.axisX.type === undefined) {\n axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n ticks: data.normalized.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, {\n high: isNumeric(options.high) ? options.high : options.axisY.high,\n low: isNumeric(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = new options.axisY.type(axisUnits.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 createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);\n }\n\n // Draw the series\n data.raw.series.forEach((series, seriesIndex) => {\n const 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': 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}-${alphaNumerate(seriesIndex)}`\n ].join(' '));\n\n const pathCoordinates = [];\n const pathData = [];\n\n data.normalized.series[seriesIndex].forEach((value, valueIndex) => {\n const 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,\n valueIndex,\n meta: getMetaData(series, valueIndex)\n });\n });\n\n const seriesOptions = {\n lineSmooth: getSeriesOption(series, options, 'lineSmooth'),\n showPoint: getSeriesOption(series, options, 'showPoint'),\n showLine: getSeriesOption(series, options, 'showLine'),\n showArea: getSeriesOption(series, options, 'showArea'),\n areaBase: getSeriesOption(series, options, 'areaBase')\n };\n\n let smoothing;\n if(typeof seriesOptions.lineSmooth === 'function') {\n smoothing = seriesOptions.lineSmooth;\n } else {\n smoothing = seriesOptions.lineSmooth ? monotoneCubic() : none();\n }\n\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 const 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((pathElement) => {\n const 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(isNumeric).join(','),\n 'ct:meta': 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,\n seriesIndex,\n axisX,\n axisY,\n group: seriesElement,\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n });\n }\n\n if(seriesOptions.showLine) {\n const 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,\n // TODO: Remove redundant\n index: seriesIndex,\n series,\n seriesIndex,\n seriesMeta: series.meta,\n axisX,\n 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 const areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min);\n\n // We project the areaBase value into screen coordinates\n const 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')\n // We filter only \"solid\" segments that contain more than one point. Otherwise there's no need for an area\n .filter((pathSegment) => pathSegment.pathElements.length > 1)\n .map((solidPathSegments) => {\n // Receiving the filtered solid path segments we can now convert those segments into fill areas\n const firstElement = solidPathSegments.pathElements[0];\n const 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 })\n .forEach((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 const 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,\n seriesIndex,\n axisX,\n axisY,\n chartRect,\n // TODO: Remove redundant\n index: seriesIndex,\n group: seriesElement,\n element: area\n });\n });\n }\n });\n\n this.eventEmitter.emit('created', {\n // TODO: Remove redundant\n bounds: axisY.bounds,\n chartRect,\n axisX,\n axisY,\n svg: this.svg,\n options\n });\n }\n}\n","import {isNumeric, alphaNumerate} from '../core/lang';\nimport {noop, serialMap} from '../core/functional';\nimport {extend} from '../core/extend';\nimport {normalizeData, serialize, getMetaData, getHighLow} from '../core/data';\nimport {createSvg, createChartRect, createGridBackground} from '../core/creation';\nimport {AutoScaleAxis, StepAxis, axisUnits} from '../axes/axes';\nimport {BaseChart} from './base';\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 */\nconst 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: 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: 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\nexport class BarChart extends BaseChart {\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 constructor(query, data, options, responsiveOptions) {\n super(query, data, defaultOptions, extend({}, defaultOptions, options), responsiveOptions);\n }\n\n /**\n * Creates a new chart\n *\n */\n createChart(options) {\n let data;\n let highLow;\n\n if(options.distributeSeries) {\n data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n data.normalized.series = data.normalized.series.map((value) => [value]);\n } else {\n data = normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n }\n\n // Create new svg element\n this.svg = 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 const gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n const seriesGroup = this.svg.elem('g');\n const labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);\n\n if(options.stackBars && data.normalized.series.length !== 0) {\n // If stacked bars we need to calculate the high low from stacked values from each series\n const serialSums = serialMap(data.normalized.series, () =>\n Array.from(arguments)\n .map((value) => value)\n .reduce((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 = getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y');\n\n } else {\n highLow = 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 const chartRect = createChartRect(this.svg, options, defaultOptions.padding);\n let valueAxis;\n let labelAxisTicks;\n let labelAxis;\n let axisX;\n let 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 AutoScaleAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n\n if(options.axisY.type === undefined) {\n labelAxis = axisY = new StepAxis(axisUnits.y, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisY = new options.axisY.type(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n }\n\n // Projected 0 point\n const zeroPoint = options.horizontalBars ?\n (chartRect.x1 + valueAxis.projectValue(0)) :\n (chartRect.y1 - valueAxis.projectValue(0));\n // Used to track the screen coordinates of stacked bars\n const 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 createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);\n }\n\n // Draw the series\n data.raw.series.forEach((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 const biPol = seriesIndex - (data.raw.series.length - 1) / 2;\n // Half of the period width between vertical grid lines used to position bars\n let periodHalfLength;\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 const 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': 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}-${alphaNumerate(seriesIndex)}`\n ].join(' '));\n\n data.normalized.series[seriesIndex].forEach((value, valueIndex) => {\n let labelAxisValueIndex;\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 let projected;\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 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 const 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 const 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 const metaData = getMetaData(series, valueIndex);\n\n // Create bar element\n const bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(isNumeric).join(','),\n 'ct:meta': serialize(metaData)\n });\n\n this.eventEmitter.emit('draw', extend({\n type: 'bar',\n value,\n index: valueIndex,\n meta: metaData,\n series,\n seriesIndex,\n axisX,\n axisY,\n chartRect,\n group: seriesElement,\n element: bar\n }, positions));\n });\n });\n\n this.eventEmitter.emit('created', {\n bounds: valueAxis.bounds,\n chartRect,\n axisX,\n axisY,\n svg: this.svg,\n options\n });\n }\n}\n"]} \ No newline at end of file diff --git a/package.json b/package.json index 55df6472..9d8a8dcb 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,15 @@ ], "dependencies": {}, "devDependencies": { + "autoprefixer": "^6.5.1", + "babel-eslint": "^7.1.0", "browser-sync": "^2.17.5", + "chokidar": "^1.6.1", + "cssnano": "^3.7.7", + "debounce": "^1.0.0", + "eslint": "^3.8.1", + "fs-promise": "^0.5.0", + "interpolate": "^0.1.0", "jasmine-core": "^2.5.2", "jspm": "beta", "karma": "^1.3.0", @@ -49,12 +57,6 @@ "karma-jspm": "^2.2.0", "karma-nyan-reporter": "^0.2.4", "karma-phantomjs-launcher": "^1.0.2", - "autoprefixer": "^6.5.1", - "chokidar": "^1.6.1", - "cssnano": "^3.7.7", - "debounce": "^1.0.0", - "fs-promise": "^0.5.0", - "interpolate": "^0.1.0", "node-sass": "^3.10.1", "postcss": "^5.2.5" }, @@ -77,12 +79,13 @@ "test-watch": "./node_modules/.bin/karma start karma.watch.config.js", "styles-watch": "./tooling/node/styles-watch.js", "server": "./node_modules/.bin/browser-sync start --config 'bs-config.js'", - "build": "yarn run build-styles && yarn run build-umd && yarn run build-esm", + "lint": "./node_modules/.bin/eslint src", + "build": "yarn run lint && yarn run build-styles && yarn run test && yarn run build-umd && yarn run build-esm", "build-umd": "./node_modules/.bin/jspm build chartist dist/chartist.umd.js --format umd --global-name Chartist --minify --source-map-contents && ./tooling/node/banner.js dist/chartist.umd.js dist/chartist.umd.js", "build-esm": "./node_modules/.bin/jspm build chartist dist/chartist.esm.js --format esm && ./tooling/node/banner.js dist/chartist.esm.js dist/chartist.esm.js", "build-styles": "./tooling/node/styles.js src/styles/chartist.scss dist" }, "config": { - "banner": "/* Chartist.js {pkg.version}\n * Copyright © {year} 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" + "banner": "/* Chartist.js {pkg.version}\n * Copyright © {year} Gion Kunz\n * Free to use under either the WTFPL license or the MIT license.\n * https://raw.githubusercontent.com/chartist-js/chartist/master/LICENSE-WTFPL\n * https://raw.githubusercontent.com/chartist-js/chartist/master/LICENSE-MIT\n */\n" } } diff --git a/src/axes/axis.js b/src/axes/axis.js index 09119ca2..c08cef1b 100644 --- a/src/axes/axis.js +++ b/src/axes/axis.js @@ -107,7 +107,7 @@ export class Axis { createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [ chartOptions.classNames.label, chartOptions.classNames[this.units.dir], - (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']) + (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames.end) ], useForeignObject, eventEmitter); } }); diff --git a/src/axes/axis.spec.js b/src/axes/axis.spec.js index fd3b579c..bf60703a 100644 --- a/src/axes/axis.spec.js +++ b/src/axes/axis.spec.js @@ -57,7 +57,7 @@ describe('Axis', () => { chartOptions.axisX.labelInterpolationFnc = (value, index) => index === 0 ? null : value; - var axis = new Axis(); + const axis = new Axis(); axis.initialize(axisUnits.x, chartRect, ticks, null); axis.projectValue = (value) => value; @@ -70,7 +70,7 @@ describe('Axis', () => { chartOptions.axisX.labelInterpolationFnc = (value, index) => index === 0 ? undefined : value; - var axis = new Axis(); + const axis = new Axis(); axis.initialize(axisUnits.x, chartRect, ticks, null); axis.projectValue = (value) => value; @@ -83,7 +83,7 @@ describe('Axis', () => { chartOptions.axisX.labelInterpolationFnc = (value, index) => index === 0 ? '' : value; - var axis = new Axis(); + const axis = new Axis(); axis.initialize(axisUnits.x, chartRect, ticks, null); axis.projectValue = (value) => value; diff --git a/src/charts/bar.js b/src/charts/bar.js index 2525abc1..23940417 100644 --- a/src/charts/bar.js +++ b/src/charts/bar.js @@ -178,7 +178,7 @@ export class BarChart extends BaseChart { if(options.stackBars && data.normalized.series.length !== 0) { // If stacked bars we need to calculate the high low from stacked values from each series - var serialSums = serialMap(data.normalized.series, () => + const serialSums = serialMap(data.normalized.series, () => Array.from(arguments) .map((value) => value) .reduce((prev, curr) => { @@ -271,7 +271,7 @@ export class BarChart extends BaseChart { labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); - if (options.showGridBackground) { + if(options.showGridBackground) { createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); } diff --git a/src/charts/bar.spec.js b/src/charts/bar.spec.js index 133c8459..4dd54581 100644 --- a/src/charts/bar.spec.js +++ b/src/charts/bar.spec.js @@ -30,11 +30,11 @@ describe('BarChart', () => { beforeEach(() => { data = { series: [[ - { x: 1, y: 1 }, - { x: 3, y: 5 } + {x: 1, y: 1}, + {x: 3, y: 5} ]] }; - options = { + options = { axisX: { type: AutoScaleAxis, onlyInteger: true @@ -250,7 +250,7 @@ describe('BarChart', () => { it('should generate labels and render empty grid with only series in data', (done) => { data = { - series: [ + series: [ [1, 2, 3, 4], [2, 3, 4], [3, 4] diff --git a/src/charts/line.js b/src/charts/line.js index caf498ff..ee9f0fef 100644 --- a/src/charts/line.js +++ b/src/charts/line.js @@ -211,7 +211,7 @@ export class LineChart extends BaseChart { let axisX; let axisY; - if (options.axisX.type === undefined) { + if(options.axisX.type === undefined) { axisX = new StepAxis(axisUnits.x, data.normalized.series, chartRect, extend({}, options.axisX, { ticks: data.normalized.labels, stretch: options.fullWidth @@ -220,7 +220,7 @@ export class LineChart extends BaseChart { axisX = new options.axisX.type(axisUnits.x, data.normalized.series, chartRect, options.axisX); } - if (options.axisY.type === undefined) { + if(options.axisY.type === undefined) { axisY = new AutoScaleAxis(axisUnits.y, data.normalized.series, chartRect, extend({}, options.axisY, { high: isNumeric(options.high) ? options.high : options.axisY.high, low: isNumeric(options.low) ? options.low : options.axisY.low @@ -232,7 +232,7 @@ export class LineChart extends BaseChart { axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); - if (options.showGridBackground) { + if(options.showGridBackground) { createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); } @@ -276,8 +276,13 @@ export class LineChart extends BaseChart { areaBase: getSeriesOption(series, options, 'areaBase') }; - const smoothing = typeof seriesOptions.lineSmooth === 'function' ? - seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? monotoneCubic() : none()); + let smoothing; + if(typeof seriesOptions.lineSmooth === 'function') { + smoothing = seriesOptions.lineSmooth; + } else { + smoothing = seriesOptions.lineSmooth ? monotoneCubic() : none(); + } + // Interpolating path where pathData will be used to annotate each path element so we can trace back the original // index, value and meta data const path = smoothing(pathCoordinates, pathData); @@ -285,7 +290,7 @@ export class LineChart extends BaseChart { // If we should show points we need to create them now to avoid secondary loop // Points are drawn from the pathElements returned by the interpolation function // Small offset for Firefox to render squares correctly - if (seriesOptions.showPoint) { + if(seriesOptions.showPoint) { path.pathElements.forEach((pathElement) => { const point = seriesElement.elem('line', { @@ -315,7 +320,7 @@ export class LineChart extends BaseChart { }); } - if (seriesOptions.showLine) { + if(seriesOptions.showLine) { const line = seriesElement.elem('path', { d: path.stringify() }, options.classNames.line, true); @@ -338,7 +343,7 @@ export class LineChart extends BaseChart { } // Area currently only works with axes that support a range! - if (seriesOptions.showArea && axisY.range) { + if(seriesOptions.showArea && axisY.range) { // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that // the area is not drawn outside the chart area. const areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); @@ -348,7 +353,7 @@ export class LineChart extends BaseChart { // In order to form the area we'll first split the path by move commands so we can chunk it up into segments path.splitByCommand('M') - // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area + // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area .filter((pathSegment) => pathSegment.pathElements.length > 1) .map((solidPathSegments) => { // Receiving the filtered solid path segments we can now convert those segments into fill areas @@ -393,7 +398,7 @@ export class LineChart extends BaseChart { }); } }); - + this.eventEmitter.emit('created', { // TODO: Remove redundant bounds: axisY.bounds, diff --git a/src/charts/line.spec.js b/src/charts/line.spec.js index 00435294..871416b7 100644 --- a/src/charts/line.spec.js +++ b/src/charts/line.spec.js @@ -31,11 +31,11 @@ describe('LineChart', () => { beforeEach(() => { data = { series: [[ - { x: 1, y: 1 }, - { x: 3, y: 5 } + {x: 1, y: 1}, + {x: 3, y: 5} ]] }; - options = { + options = { axisX: { type: AutoScaleAxis, onlyInteger: true @@ -83,11 +83,11 @@ describe('LineChart', () => { beforeEach(() => { data = { series: [[ - { x: 1, y: 1 }, - { x: 3, y: 5 } + {x: 1, y: 1}, + {x: 3, y: 5} ]] }; - options = {}; + options = {}; }); it('should have ct-start class if position start', (done) => { @@ -274,7 +274,7 @@ describe('LineChart', () => { const chart = createChart(); chart.on('draw', (context) => { - if (context.type === 'line') { + if(context.type === 'line') { expect(context.path.pathElements.map((pathElement) => { return { command: pathElement.command, @@ -306,7 +306,7 @@ describe('LineChart', () => { const chart = createChart(); chart.on('draw', (context) => { - if (context.type === 'line') { + if(context.type === 'line') { expect(context.path.pathElements.map((pathElement) => { return { command: pathElement.command, @@ -340,7 +340,7 @@ describe('LineChart', () => { const chart = createChart(); chart.on('draw', (context) => { - if (context.type === 'line') { + if(context.type === 'line') { expect(context.path.pathElements.map((pathElement) => { return { command: pathElement.command, @@ -374,7 +374,7 @@ describe('LineChart', () => { const chart = createChart(); chart.on('draw', (context) => { - if (context.type === 'line') { + if(context.type === 'line') { expect(context.path.pathElements.map((pathElement) => { return { command: pathElement.command, @@ -406,7 +406,7 @@ describe('LineChart', () => { const chart = createChart(); chart.on('draw', (context) => { - if (context.type === 'line') { + if(context.type === 'line') { expect(context.path.pathElements.map((pathElement) => { return { command: pathElement.command, @@ -435,7 +435,7 @@ describe('LineChart', () => { [NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null] ] }; - options ={ + options = { lineSmooth: Interpolation.step({ postpone: false }) @@ -443,7 +443,7 @@ describe('LineChart', () => { const chart = createChart(); chart.on('draw', (context) => { - if (context.type === 'line') { + if(context.type === 'line') { expect(context.path.pathElements.map((pathElement) => { return { command: pathElement.command, @@ -509,7 +509,7 @@ describe('LineChart', () => { it('should generate labels and render empty grid with only series in data', (done) => { data = { - series: [ + series: [ [1, 2, 3, 4], [2, 3, 4], [3, 4] @@ -528,7 +528,7 @@ describe('LineChart', () => { it('should render empty grid with no data and specified high low', (done) => { data = null; - options ={ + options = { width: 400, height: 300, high: 100, diff --git a/src/charts/pie.js b/src/charts/pie.js index ee0089e5..820dcec9 100644 --- a/src/charts/pie.js +++ b/src/charts/pie.js @@ -64,10 +64,10 @@ const defaultOptions = { export function determineAnchorPosition(center, label, direction) { const toTheRight = label.x > center.x; - if (toTheRight && direction === 'explode' || + if(toTheRight && direction === 'explode' || !toTheRight && direction === 'implode') { return 'start'; - } else if (toTheRight && direction === 'implode' || + } else if(toTheRight && direction === 'implode' || !toTheRight && direction === 'explode') { return 'end'; } else { @@ -171,7 +171,7 @@ export class PieChart extends BaseChart { data.normalized.series.reduce(sum, 0); const donutWidth = quantity(options.donutWidth); - if (donutWidth.unit === '%') { + if(donutWidth.unit === '%') { donutWidth.value *= radius / 100; } @@ -182,9 +182,9 @@ export class PieChart extends BaseChart { // 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) { labelRadius = radius; - } else if (options.labelPosition === 'center') { + } else if(options.labelPosition === 'center') { // If labelPosition is center we start with 0 and will later wait for the labelOffset labelRadius = 0; } else { @@ -203,14 +203,14 @@ export class PieChart extends BaseChart { // Check if there is only one non-zero value in the series array. const hasSingleValInSeries = data.raw.series - .filter((val) => val.hasOwnProperty('value') ? val.value !== 0 : val !== 0) - .length === 1; + .filter((val) => val.hasOwnProperty('value') ? val.value !== 0 : val !== 0) + .length === 1; // Creating the series groups data.raw.series .forEach((series, index) => seriesGroups[index] = this.svg.elem('g', null, null)); - //if we need to show labels we create the label group now - if (options.showLabel) { + // if we need to show labels we create the label group now + if(options.showLabel) { labelsGroup = this.svg.elem('g', null, null); } @@ -218,7 +218,9 @@ export class PieChart extends BaseChart { // initialize series groups data.raw.series.forEach((series, index) => { // If current value is zero and we are ignoring empty values then skip to next value - if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; + if(data.normalized.series[index] === 0 && options.ignoreEmptyValues) { + return; + } // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[index].attr({ @@ -239,7 +241,7 @@ export class PieChart extends BaseChart { // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees - if (endAngle - overlappigStartAngle >= 359.99) { + if(endAngle - overlappigStartAngle >= 359.99) { endAngle = overlappigStartAngle + 359.99; } @@ -252,7 +254,7 @@ export class PieChart extends BaseChart { .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) { + if(!options.donut) { path.line(center.x, center.y); } @@ -269,7 +271,7 @@ export class PieChart extends BaseChart { }); // If this is a donut, we add the stroke-width as style attribute - if (options.donut) { + if(options.donut) { pathElement.attr({ 'style': 'stroke-width: ' + donutWidth.value + 'px' }); @@ -293,10 +295,10 @@ export class PieChart extends BaseChart { }); // If we need to show labels we need to add the label for this slice now - if (options.showLabel) { + if(options.showLabel) { let labelPosition; - if (data.raw.series.length === 1) { + if(data.raw.series.length === 1) { // If we have only 1 series, we can position the label in the center of the pie labelPosition = { x: center.x, @@ -313,7 +315,7 @@ export class PieChart extends BaseChart { } let rawValue; - if (data.normalized.labels && !isFalseyButZero(data.normalized.labels[index])) { + if(data.normalized.labels && !isFalseyButZero(data.normalized.labels[index])) { rawValue = data.normalized.labels[index]; } else { rawValue = data.normalized.series[index]; @@ -321,8 +323,8 @@ export class PieChart extends BaseChart { const interpolatedValue = options.labelInterpolationFnc(rawValue, index); - if (interpolatedValue || interpolatedValue === 0) { - var labelElement = labelsGroup.elem('text', { + if(interpolatedValue || interpolatedValue === 0) { + const labelElement = labelsGroup.elem('text', { dx: labelPosition.x, dy: labelPosition.y, 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) diff --git a/src/charts/pie.spec.js b/src/charts/pie.spec.js index c0a7e2ba..309a9f39 100644 --- a/src/charts/pie.spec.js +++ b/src/charts/pie.spec.js @@ -285,7 +285,7 @@ describe('PieChart', () => { data = { series: [1, 2, 0, 4] }; - options = { + options = { width: 100, height: 100, ignoreEmptyValues: false diff --git a/src/core/creation.js b/src/core/creation.js index 623f2fe6..88ba77c3 100644 --- a/src/core/creation.js +++ b/src/core/creation.js @@ -89,8 +89,8 @@ export function createChartRect(svg, options, fallbackPadding) { } }; - if (hasAxis) { - if (options.axisX.position === 'start') { + if(hasAxis) { + if(options.axisX.position === 'start') { chartRect.y2 = normalizedPadding.top + xAxisOffset; chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); } else { @@ -98,7 +98,7 @@ export function createChartRect(svg, options, fallbackPadding) { chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1); } - if (options.axisY.position === 'start') { + if(options.axisY.position === 'start') { chartRect.x1 = normalizedPadding.left + yAxisOffset; chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); } else { @@ -199,14 +199,14 @@ export function createLabel(position, length, index, labels, axis, axisOffset, l positionalData[axis.units.len] = length; positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10); - if (useForeignObject) { + 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 - const length = Math.round(positionalData[axis.units.len]); - const counterLength = Math.round(positionalData[axis.counterUnits.len]); + const stepLength = Math.round(positionalData[axis.units.len]); + const stepCounterLength = Math.round(positionalData[axis.counterUnits.len]); const content = ` + style="${axis.units.len}: ${stepLength}px; ${axis.counterUnits.len}: ${stepCounterLength}px"> ${labels[index]} `.trim(); diff --git a/src/core/creation.spec.js b/src/core/creation.spec.js index 59baf789..3ca3ef90 100644 --- a/src/core/creation.spec.js +++ b/src/core/creation.spec.js @@ -28,7 +28,7 @@ describe('Creation', () => { }); it('should remove previous chartist svg elements', () => { - const fixture = addFixture(`
    `); + const fixture = addFixture('
    '); const container = fixture.wrapper.querySelector('#chart-container'); const svg1 = createSvg(container, '500px', '400px', 'ct-fish-bar'); diff --git a/src/core/data.js b/src/core/data.js index 19ebcb98..86b7b3cd 100644 --- a/src/core/data.js +++ b/src/core/data.js @@ -161,7 +161,7 @@ export function getDataArray(data, reverse, multi) { } else { // We need to prepare multi value output (x and y data) if(multi) { - var multiValue = {}; + const multiValue = {}; // Single series value arrays are assumed to specify the Y-Axis value // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] @@ -321,15 +321,15 @@ export function getHighLow(data, options, dimension) { const findLow = options.low === undefined; // Function to recursively walk through arrays and find highest and lowest number - function recursiveHighLow(data) { - if(data === undefined) { + function recursiveHighLow(sourceData) { + if(sourceData === undefined) { return undefined; - } else if(data instanceof Array) { - for(let i = 0; i < data.length; i++) { - recursiveHighLow(data[i]); + } else if(sourceData instanceof Array) { + for(let i = 0; i < sourceData.length; i++) { + recursiveHighLow(sourceData[i]); } } else { - const value = dimension ? +data[dimension] : +data; + const value = dimension ? +sourceData[dimension] : +sourceData; if(findHigh && value > highLow.high) { highLow.high = value; @@ -460,7 +460,7 @@ export function getBounds(axisLength, highLow, scaleMinSpace, onlyInteger) { const values = []; for(let i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { - var value = roundWithPrecision(i); + const value = roundWithPrecision(i); if(value !== values[values.length - 1]) { values.push(value); } diff --git a/src/core/functional.js b/src/core/functional.js index fbb92d88..461c5bcb 100644 --- a/src/core/functional.js +++ b/src/core/functional.js @@ -41,10 +41,10 @@ export const sum = (previous, current) => previous + (current ? current : 0); * ``` * * @memberof Chartist.Core - * @param arr - * @param cb + * @param array + * @param callback * @return {Array} */ -export const serialMap = (arr, cb) => - times(Math.max(...arr.map((e) => e.length))) - .map((e, index) => cb(...arr.map((e) => e[index]))); +export const serialMap = (array, callback) => + times(Math.max(...array.map((element) => element.length))) + .map((inner, index) => callback(...array.map((element) => element[index]))); diff --git a/src/core/lang.js b/src/core/lang.js index 8d35b22f..72f606e6 100644 --- a/src/core/lang.js +++ b/src/core/lang.js @@ -91,10 +91,10 @@ export function ensureUnit(value, unit) { * @return {Object} Returns an object containing the value as number and the unit as string. */ export function quantity(input) { - if (typeof input === 'string') { + if(typeof input === 'string') { const match = (/^(\d+)\s*(.*)$/g).exec(input); return { - value : +match[1], + value: +match[1], unit: match[2] || undefined }; } diff --git a/src/core/math.js b/src/core/math.js index 0dadbbe0..d6b21ede 100644 --- a/src/core/math.js +++ b/src/core/math.js @@ -52,7 +52,7 @@ export function rho(num) { } function gcd(p, q) { - if (p % q === 0) { + if(p % q === 0) { return q; } else { return gcd(q, p % q); @@ -66,7 +66,7 @@ export function rho(num) { let x1 = 2; let x2 = 2; let divisor; - if (num % 2 === 0) { + if(num % 2 === 0) { return 2; } @@ -74,7 +74,7 @@ export function rho(num) { x1 = f(x1) % num; x2 = f(f(x2)) % num; divisor = gcd(Math.abs(x1 - x2), num); - } while (divisor === 1); + } while(divisor === 1); return divisor; } diff --git a/src/core/options-provider.js b/src/core/options-provider.js index b6dff106..05895064 100644 --- a/src/core/options-provider.js +++ b/src/core/options-provider.js @@ -18,10 +18,10 @@ export function optionsProvider(options, responsiveOptions, eventEmitter) { const previousOptions = currentOptions; currentOptions = extend({}, baseOptions); - if (responsiveOptions) { + if(responsiveOptions) { responsiveOptions.forEach((responsiveOption) => { const mql = window.matchMedia(responsiveOption[0]); - if (mql.matches) { + if(mql.matches) { currentOptions = extend(currentOptions, responsiveOption[1]); } }); @@ -39,9 +39,9 @@ export function optionsProvider(options, responsiveOptions, eventEmitter) { mediaQueryListeners.forEach((mql) => mql.removeListener(updateCurrentOptions)); } - if (!window.matchMedia) { + if(!window.matchMedia) { throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; - } else if (responsiveOptions) { + } else if(responsiveOptions) { responsiveOptions.forEach((responsiveOption) => { const mql = window.matchMedia(responsiveOption[0]); mql.addListener(updateCurrentOptions); diff --git a/src/interpolation/cardinal.js b/src/interpolation/cardinal.js index ae501000..ecf982f3 100644 --- a/src/interpolation/cardinal.js +++ b/src/interpolation/cardinal.js @@ -35,7 +35,7 @@ export function cardinal(options) { const t = Math.min(1, Math.max(0, options.tension)); const c = 1 - t; - return function cardinal(pathCoordinates, valueData) { + return function cardinalInterpolation(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts const segments = splitIntoSegments(pathCoordinates, valueData, { @@ -51,7 +51,7 @@ export function cardinal(options) { // For each segment we will recurse the cardinal function // Join the segment path data into a single path and return return SvgPath.join( - segments.map((segment) => cardinal(segment.pathCoordinates, segment.valueData)) + segments.map((segment) => cardinalInterpolation(segment.pathCoordinates, segment.valueData)) ); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first diff --git a/src/interpolation/monotone-cubic.js b/src/interpolation/monotone-cubic.js index 1bdb069d..00469598 100644 --- a/src/interpolation/monotone-cubic.js +++ b/src/interpolation/monotone-cubic.js @@ -32,7 +32,7 @@ export function monotoneCubic(options) { options = extend({}, defaultOptions, options); - return function monotoneCubic(pathCoordinates, valueData) { + return function monotoneCubicInterpolation(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts const segments = splitIntoSegments(pathCoordinates, valueData, { @@ -49,7 +49,7 @@ export function monotoneCubic(options) { // For each segment we will recurse the monotoneCubic fn function // Join the segment path data into a single path and return return SvgPath.join( - segments.map((segment) => monotoneCubic(segment.pathCoordinates, segment.valueData)) + segments.map((segment) => monotoneCubicInterpolation(segment.pathCoordinates, segment.valueData)) ); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first diff --git a/src/interpolation/none.js b/src/interpolation/none.js index 777e728a..90c64246 100644 --- a/src/interpolation/none.js +++ b/src/interpolation/none.js @@ -25,7 +25,7 @@ export function none(options) { options = extend({}, defaultOptions, options); - return function none(pathCoordinates, valueData) { + return function noneInterpolation(pathCoordinates, valueData) { const path = new SvgPath(); let hole = true; diff --git a/src/interpolation/simple.js b/src/interpolation/simple.js index bec2b7d8..839d6c3b 100644 --- a/src/interpolation/simple.js +++ b/src/interpolation/simple.js @@ -34,7 +34,7 @@ export function simple(options) { const d = 1 / Math.max(1, options.divisor); - return function simple(pathCoordinates, valueData) { + return function simpleInterpolation(pathCoordinates, valueData) { const path = new SvgPath(); let prevX; let prevY; diff --git a/src/interpolation/step.js b/src/interpolation/step.js index 2581c50b..91513f28 100644 --- a/src/interpolation/step.js +++ b/src/interpolation/step.js @@ -29,14 +29,14 @@ export function step(options) { options = extend({}, defaultOptions, options); - return function step(pathCoordinates, valueData) { + return function stepInterpolation(pathCoordinates, valueData) { const path = new SvgPath(); let prevX; let prevY; let prevData; - for (let i = 0; i < pathCoordinates.length; i += 2) { + for(let i = 0; i < pathCoordinates.length; i += 2) { const currX = pathCoordinates[i]; const currY = pathCoordinates[i + 1]; const currData = valueData[i / 2]; diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index e3caaa6b..41f78fc9 100644 --- a/src/styles/chartist.scss +++ b/src/styles/chartist.scss @@ -38,7 +38,7 @@ -ms-flex-pack: $ct-text-justify; justify-content: $ct-text-justify; // Fallback to text-align for non-flex browsers - @if($ct-text-justify == 'flex-start') { + @if ($ct-text-justify == 'flex-start') { text-align: left; } @else if ($ct-text-justify == 'flex-end') { text-align: right; diff --git a/src/svg/svg-list.js b/src/svg/svg-list.js index b56d40b6..aec6746a 100644 --- a/src/svg/svg-list.js +++ b/src/svg/svg-list.js @@ -10,32 +10,32 @@ import {Svg} from './svg'; */ export class SvgList { constructor(nodeList) { - var list = this; + const list = this; this.svgElements = []; - for(var i = 0; i < nodeList.length; i++) { + for(let i = 0; i < nodeList.length; i++) { this.svgElements.push(new Svg(nodeList[i])); } // Add delegation methods for Svg - Object.keys(Svg.prototype).filter(function(prototypeProperty) { - return ['constructor', - 'parent', - 'querySelector', - 'querySelectorAll', - 'replace', - 'append', - 'classes', - 'height', - 'width'].indexOf(prototypeProperty) === -1; - }).forEach(function(prototypeProperty) { - list[prototypeProperty] = function() { - var args = Array.prototype.slice.call(arguments, 0); - list.svgElements.forEach(function(element) { - Svg.prototype[prototypeProperty].apply(element, args); - }); - return list; - }; - }); + Object.keys(Svg.prototype).filter((prototypeProperty) => [ + 'constructor', + 'parent', + 'querySelector', + 'querySelectorAll', + 'replace', + 'append', + 'classes', + 'height', + 'width' + ].indexOf(prototypeProperty) === -1) + .forEach((prototypeProperty) => { + list[prototypeProperty] = () => { + const args = Array.from(arguments); + list.svgElements.forEach((element) => + Svg.prototype[prototypeProperty].apply(element, args)); + return list; + }; + }); } } diff --git a/src/svg/svg-path.js b/src/svg/svg-path.js index d634d9ee..c59d6d18 100644 --- a/src/svg/svg-path.js +++ b/src/svg/svg-path.js @@ -25,16 +25,16 @@ const defaultOptions = { }; function element(command, params, pathElements, pos, relative, data) { - var pathElement = extend({ + const pathElement = extend({ command: relative ? command.toLowerCase() : command.toUpperCase() - }, params, data ? { data: data } : {} ); + }, params, data ? {data: data} : {}); pathElements.splice(pos, 0, pathElement); } function forEachParam(pathElements, cb) { - pathElements.forEach(function(pathElement, pathElementIndex) { - elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) { + pathElements.forEach((pathElement, pathElementIndex) => { + elementDescriptions[pathElement.command.toLowerCase()].forEach((paramName, paramIndex) => { cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); }); }); @@ -59,10 +59,10 @@ export class SvgPath { * @return {SvgPath} */ static join(paths, close, options) { - var joinedPath = new SvgPath(close, options); - for(var i = 0; i < paths.length; i++) { - var path = paths[i]; - for(var j = 0; j < path.pathElements.length; j++) { + const joinedPath = new SvgPath(close, options); + for(let i = 0; i < paths.length; i++) { + const path = paths[i]; + for(let j = 0; j < path.pathElements.length; j++) { joinedPath.pathElements.push(path.pathElements[j]); } } @@ -203,15 +203,15 @@ export class SvgPath { */ parse(path) { // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] - var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') + const chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') .replace(/([0-9])([A-Za-z])/g, '$1 $2') .split(/[\s,]+/) - .reduce(function(result, element) { - if(element.match(/[A-Za-z]/)) { + .reduce((result, pathElement) => { + if(pathElement.match(/[A-Za-z]/)) { result.push([]); } - result[result.length - 1].push(element); + result[result.length - 1].push(pathElement); return result; }, []); @@ -222,22 +222,20 @@ export class SvgPath { // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters // For example {command: 'M', x: '10', y: '10'} - var elements = chunks.map(function(chunk) { - var command = chunk.shift(), - description = elementDescriptions[command.toLowerCase()]; + const elements = chunks.map((chunk) => { + const command = chunk.shift(); + const description = elementDescriptions[command.toLowerCase()]; return extend({ command: command - }, description.reduce(function(result, paramName, index) { + }, description.reduce((result, paramName, index) => { result[paramName] = +chunk[index]; return result; }, {})); }); // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position - var spliceArgs = [this.pos, 0]; - Array.prototype.push.apply(spliceArgs, elements); - Array.prototype.splice.apply(this.pathElements, spliceArgs); + this.pathElements.splice(this.pos, 0, ...elements); // Increase the internal position by the element count this.pos += elements.length; @@ -251,17 +249,17 @@ export class SvgPath { * @return {String} */ stringify() { - var accuracyMultiplier = Math.pow(10, this.options.accuracy); + const accuracyMultiplier = Math.pow(10, this.options.accuracy); - return this.pathElements.reduce(function(path, pathElement) { - var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) { - return this.options.accuracy ? + return this.pathElements.reduce((path, pathElement) => { + const params = elementDescriptions[pathElement.command.toLowerCase()].map((paramName) => + this.options.accuracy ? (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) : - pathElement[paramName]; - }.bind(this)); + pathElement[paramName] + ); return path + pathElement.command + params.join(','); - }.bind(this), '') + (this.close ? 'Z' : ''); + }, '') + (this.close ? 'Z' : ''); } /** @@ -273,9 +271,9 @@ export class SvgPath { * @return {SvgPath} The current path object for easy call chaining. */ scale(x, y) { - forEachParam(this.pathElements, function(pathElement, paramName) { - pathElement[paramName] *= paramName[0] === 'x' ? x : y; - }); + forEachParam(this.pathElements, (pathElement, paramName) => + pathElement[paramName] *= paramName[0] === 'x' ? x : y + ); return this; } @@ -288,9 +286,9 @@ export class SvgPath { * @return {SvgPath} The current path object for easy call chaining. */ translate(x, y) { - forEachParam(this.pathElements, function(pathElement, paramName) { - pathElement[paramName] += paramName[0] === 'x' ? x : y; - }); + forEachParam(this.pathElements, (pathElement, paramName) => + pathElement[paramName] += paramName[0] === 'x' ? x : y + ); return this; } @@ -307,8 +305,8 @@ export class SvgPath { * @return {SvgPath} The current path object for easy call chaining. */ transform(transformFnc) { - forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) { - var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); + forEachParam(this.pathElements, (pathElement, paramName, pathElementIndex, paramIndex, pathElements) => { + const transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); if(transformed || transformed === 0) { pathElement[paramName] = transformed; } @@ -324,13 +322,11 @@ export class SvgPath { * @return {SvgPath} */ clone(close) { - var c = new SvgPath(close || this.close); - c.pos = this.pos; - c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { - return extend({}, pathElement); - }); - c.options = extend({}, this.options); - return c; + const clone = new SvgPath(close || this.close); + clone.pos = this.pos; + clone.pathElements = this.pathElements.slice().map((pathElement) => extend({}, pathElement)); + clone.options = extend({}, this.options); + return clone; } /** @@ -341,11 +337,11 @@ export class SvgPath { * @return {Array} */ splitByCommand(command) { - var split = [ + const split = [ new SvgPath() ]; - this.pathElements.forEach(function(pathElement) { + this.pathElements.forEach((pathElement) => { if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) { split.push(new SvgPath()); } diff --git a/src/svg/svg-path.spec.js b/src/svg/svg-path.spec.js index ee04d546..4d2dd487 100644 --- a/src/svg/svg-path.spec.js +++ b/src/svg/svg-path.spec.js @@ -22,12 +22,12 @@ describe('SvgPath', () => { expect(path.pathElements.length).toBe(6); expect(path.pathElements).toEqual([ - { command: 'M', x: 1, y: 2 }, - { command: 'm', x: 3, y: 4 }, - { command: 'L', x: 5, y: 6 }, - { command: 'l', x: 7, y: 8 }, - { command: 'C', x1: 9, y1: 10, x2: 11, y2: 12, x: 13, y: 14 }, - { command: 'c', x1: 15, y1: 16, x2: 17, y2: 18, x: 19, y: 20 } + {command: 'M', x: 1, y: 2}, + {command: 'm', x: 3, y: 4}, + {command: 'L', x: 5, y: 6}, + {command: 'l', x: 7, y: 8}, + {command: 'C', x1: 9, y1: 10, x2: 11, y2: 12, x: 13, y: 14}, + {command: 'c', x1: 15, y1: 16, x2: 17, y2: 18, x: 19, y: 20} ]); }); @@ -46,13 +46,13 @@ describe('SvgPath', () => { expect(path.pathElements.length).toBe(7); expect(path.pathElements).toEqual([ - { command: 'M', x: -1, y: 0 }, - { command: 'M', x: 1, y: 2 }, - { command: 'M', x: 3, y: 4 }, - { command: 'M', x: 5, y: 6 }, - { command: 'M', x: 7, y: 8 }, - { command: 'M', x: 9, y: 10 }, - { command: 'M', x: 11, y: 12 } + {command: 'M', x: -1, y: 0}, + {command: 'M', x: 1, y: 2}, + {command: 'M', x: 3, y: 4}, + {command: 'M', x: 5, y: 6}, + {command: 'M', x: 7, y: 8}, + {command: 'M', x: 9, y: 10}, + {command: 'M', x: 11, y: 12} ]); }); @@ -98,9 +98,9 @@ describe('SvgPath', () => { .scale(10, 100); expect(path.pathElements).toEqual([ - { command: 'M', x: 10, y: 200 }, - { command: 'L', x: 30, y: 400 }, - { command: 'C', x1: 50, y1: 600, x2: 70, y2: 800, x: 90, y: 1000 } + {command: 'M', x: 10, y: 200}, + {command: 'L', x: 30, y: 400}, + {command: 'C', x1: 50, y1: 600, x2: 70, y2: 800, x: 90, y: 1000} ]); }); @@ -112,9 +112,9 @@ describe('SvgPath', () => { .translate(10, 100); expect(path.pathElements).toEqual([ - { command: 'M', x: 11, y: 102 }, - { command: 'L', x: 13, y: 104 }, - { command: 'C', x1: 15, y1: 106, x2: 17, y2: 108, x: 19, y: 110 } + {command: 'M', x: 11, y: 102}, + {command: 'L', x: 13, y: 104}, + {command: 'C', x1: 15, y1: 106, x2: 17, y2: 108, x: 19, y: 110} ]); }); @@ -132,9 +132,9 @@ describe('SvgPath', () => { }); expect(path.pathElements).toEqual([ - { command: 'M', x: 1, y: 100 }, - { command: 'L', x: 3, y: 100 }, - { command: 'C', x1: 5, y1: 100, x2: 7, y2: 100, x: 0, y: 0 } + {command: 'M', x: 1, y: 100}, + {command: 'L', x: 3, y: 100}, + {command: 'C', x1: 5, y1: 100, x2: 7, y2: 100, x: 0, y: 0} ]); }); diff --git a/src/svg/svg.js b/src/svg/svg.js index 4a603404..9108e8a6 100644 --- a/src/svg/svg.js +++ b/src/svg/svg.js @@ -70,7 +70,7 @@ export class Svg { } if(key.indexOf(':') !== -1) { - var namespacedAttribute = key.split(':'); + const namespacedAttribute = key.split(':'); this._node.setAttributeNS(namespaces[namespacedAttribute[0]], key, attributes[key]); } else { this._node.setAttribute(key, attributes[key]); @@ -375,7 +375,7 @@ export class Svg { Object.keys(animations).forEach((attribute) => { - const createAnimate = (animationDefinition, guided) => { + const createAnimate = (animationDefinition, createGuided) => { const attributeProperties = {}; let animationEasing; let timeout; @@ -401,7 +401,7 @@ export class Svg { } // Adding "fill: freeze" if we are in guided mode and set initial attribute values - if(guided) { + if(createGuided) { animationDefinition.fill = 'freeze'; // Animated property on our element should already be set to the animation from value in guided mode attributeProperties[attribute] = animationDefinition.from; @@ -417,7 +417,7 @@ export class Svg { attributeName: attribute }, animationDefinition)); - if(guided) { + if(createGuided) { // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout setTimeout(() => { // If beginElement fails we set the animated attribute to the end position and remove the animate element @@ -454,7 +454,7 @@ export class Svg { }); } - if(guided) { + if(createGuided) { // Set animated attribute to current animated value attributeProperties[attribute] = animationDefinition.to; this.attr(attributeProperties); diff --git a/src/testing/fixtures.js b/src/testing/fixtures.js index 8501638d..28c09951 100644 --- a/src/testing/fixtures.js +++ b/src/testing/fixtures.js @@ -1,7 +1,7 @@ export let container = null; export function initializeFixtures() { - if (!container) { + if(!container) { container = document.createElement('div'); container.setAttribute('data-fixture-container', `${+new Date()}`); document.body.appendChild(container); @@ -9,14 +9,14 @@ export function initializeFixtures() { } export function destroyFixtures() { - if (container) { - document.body.removeChild(container); - container = null; - } + if(container) { + document.body.removeChild(container); + container = null; } +} export function loadFixture(path) { - if (!container) { + if(!container) { initializeFixtures(); } diff --git a/src/testing/jasmine-dom-matchers.js b/src/testing/jasmine-dom-matchers.js index d09c4b2c..ff671a43 100644 --- a/src/testing/jasmine-dom-matchers.js +++ b/src/testing/jasmine-dom-matchers.js @@ -13,9 +13,6 @@ function createCustomMatchers(matchers) { const domMatchers = { toHaveClass(actual, expected) { - console.log(actual); - console.log(expected); - const pass = actual.classList.contains(expected); return { pass, diff --git a/yarn.lock b/yarn.lock index 2c197b35..5a6b8e93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,10 +18,35 @@ accepts@1.1.4: mime-types "~2.0.4" negotiator "0.4.9" +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.3.tgz#1a3e850b428e73ba6b09d1cc527f5aaad4d03ef1" + after@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" +ajv-keywords@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.1.1.tgz#02550bc605a3e576041565628af972e06c549d50" + +ajv@^4.7.0: + version "4.8.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.8.2.tgz#65486936ca36fea39a1504332a78bebd5d447bdc" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -38,6 +63,10 @@ amdefine@>=0.0.4: version "1.0.0" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.0.tgz#fd17474700cb5cc9c2b709f0be9d23ce3c198c33" +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + ansi-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" @@ -99,6 +128,16 @@ array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" @@ -214,6 +253,15 @@ babel-core@^6.16.0, babel-core@^6.9.0: slash "^1.0.0" source-map "^0.5.0" +babel-eslint: + version "7.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.0.tgz#d506a5174ba224e25a2d17e128e2ba8987139ddc" + dependencies: + babel-traverse "^6.15.0" + babel-types "^6.15.0" + babylon "^6.11.2" + lodash.pickby "^4.6.0" + babel-generator@^6.17.0: version "6.17.0" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.17.0.tgz#b894e3808beef7800f2550635bfe024b6226cf33" @@ -305,6 +353,20 @@ babel-template@^6.14.0, babel-template@^6.16.0, babel-template@^6.9.0: babylon "^6.11.0" lodash "^4.2.0" +babel-traverse@^6.15.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.18.0.tgz#5aeaa980baed2a07c8c47329cd90c3b90c80f05e" + dependencies: + babel-code-frame "^6.16.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.18.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + babel-traverse@^6.16.0: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.16.0.tgz#fba85ae1fd4d107de9ce003149cc57f53bef0c4f" @@ -319,6 +381,15 @@ babel-traverse@^6.16.0: invariant "^2.2.0" lodash "^4.2.0" +babel-types@^6.15.0, babel-types@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.18.0.tgz#1f7d5a73474c59eb9151b2417bbff4e4fce7c3f8" + dependencies: + babel-runtime "^6.9.1" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + babel-types@^6.16.0, babel-types@^6.8.0: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.16.0.tgz#71cca1dbe5337766225c5c193071e8ebcbcffcfe" @@ -332,6 +403,10 @@ babylon@^6.11.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.13.0.tgz#58ed40dd2a8120612be5f318c2c0bedbebde4a0b" +babylon@^6.11.2: + version "6.13.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.13.1.tgz#adca350e088f0467647157652bafead6ddb8dfdb" + backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -528,10 +603,20 @@ bytes@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -566,7 +651,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -606,6 +691,10 @@ chokidar@1.6.0: optionalDependencies: fsevents "^1.0.0" +circular-json@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + clap@^1.0.9: version "1.1.1" resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.1.tgz#a8a93e0bfb7581ac199c4f001a5525a724ce696d" @@ -621,6 +710,16 @@ cli-color@^0.3.2: memoizee "~0.3.8" timers-ext "0.1" +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" @@ -641,6 +740,10 @@ clone@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + coa@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3" @@ -725,6 +828,14 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" +concat-stream@^1.4.6: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + concat-stream@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" @@ -903,10 +1014,26 @@ deep-extend@~0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -945,6 +1072,13 @@ di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + dom-serialize@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" @@ -1080,7 +1214,7 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -es5-ext@^0.10.12, es5-ext@^0.10.7, es5-ext@^0.10.9, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.5, es5-ext@~0.10.6, es5-ext@~0.10.7: +es5-ext@^0.10.12, es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@^0.10.9, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.5, es5-ext@~0.10.6, es5-ext@~0.10.7: version "0.10.12" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" dependencies: @@ -1103,11 +1237,32 @@ es6-iterator@2: es5-ext "^0.10.7" es6-symbol "3" +es6-map@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-set "~0.1.3" + es6-symbol "~3.1.0" + event-emitter "~0.3.4" + es6-promise@~4.0.3: version "4.0.5" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" -es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@3: +es6-set@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-symbol "3" + event-emitter "~0.3.4" + +es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@~3.1.0, es6-symbol@3: version "3.1.0" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" dependencies: @@ -1128,6 +1283,15 @@ es6-template-strings@^2.0.0: es5-ext "^0.10.12" esniff "^1.1" +es6-weak-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + dependencies: + d "^0.1.1" + es5-ext "^0.10.8" + es6-iterator "2" + es6-symbol "3" + es6-weak-map@~0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-0.1.4.tgz#706cef9e99aa236ba7766c239c8b9e286ea7d228" @@ -1141,10 +1305,57 @@ escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@^1.0.2: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint: + version "3.8.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.8.1.tgz#7d02db44cd5aaf4fa7aa489e1f083baa454342ba" + dependencies: + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + escope "^3.6.0" + espree "^3.3.1" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.2.0" + ignore "^3.1.5" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.6.0" + strip-bom "^3.0.0" + strip-json-comments "~1.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + esniff@^1.1: version "1.1.0" resolved "https://registry.yarnpkg.com/esniff/-/esniff-1.1.0.tgz#c66849229f91464dede2e0d40201ed6abf65f2ac" @@ -1152,10 +1363,32 @@ esniff@^1.1: d "1" es5-ext "^0.10.12" +espree@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" + dependencies: + acorn "^4.0.1" + acorn-jsx "^3.0.0" + esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -1181,6 +1414,10 @@ exec-sh@^0.2.0: dependencies: merge "^1.1.3" +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + expand-braces@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" @@ -1246,6 +1483,10 @@ extsprintf@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" +fast-levenshtein@~2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" + fb-watchman@^1.8.0: version "1.9.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.0.tgz#6f268f1f347a6b3c875d1e89da7e1ed79adfc0ec" @@ -1258,6 +1499,20 @@ fd-slicer@~1.0.1: dependencies: pend "~1.2.0" +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + filename-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" @@ -1314,6 +1569,15 @@ flagged-respawn@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5" +flat-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" + dependencies: + circular-json "^0.3.0" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" @@ -1547,6 +1811,21 @@ globals@^8.3.0: version "8.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-8.18.0.tgz#93d4a62bdcac38cfafafc47d6b034768cb0ffcb4" +globals@^9.0.0, globals@^9.2.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.12.0.tgz#992ce90828c3a55fa8f16fada177adb64664cf9d" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + globule@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/globule/-/globule-1.0.0.tgz#f22aebaacce02be492453e979c3ae9b6983f1c6c" @@ -1689,10 +1968,18 @@ iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" +ignore@^3.1.5: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" + immutable@^3.7.6, immutable@3.8.1: version "3.8.1" resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2" +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + in-publish@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" @@ -1730,6 +2017,24 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + interpolate: version "0.1.0" resolved "https://registry.yarnpkg.com/interpolate/-/interpolate-0.1.0.tgz#b60177a4ba941fb3724c821905d99aade13d1df9" @@ -1805,13 +2110,17 @@ is-fullwidth-code-point@^1.0.0: dependencies: number-is-nan "^1.0.0" +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" -is-my-json-valid@^2.12.4: +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: version "2.15.0" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" dependencies: @@ -1830,6 +2139,22 @@ is-number@^2.0.2, is-number@^2.1.0: dependencies: kind-of "^3.0.2" +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -1852,6 +2177,12 @@ is-relative@^0.2.1: dependencies: is-unc-path "^0.1.1" +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + is-stream@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -1884,7 +2215,7 @@ is@~0.2.6: version "0.2.7" resolved "https://registry.yarnpkg.com/is/-/is-0.2.7.tgz#3b34a2c48f359972f35042849193ae7264b63562" -isarray@~1.0.0, isarray@1.0.0: +isarray@^1.0.0, isarray@~1.0.0, isarray@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1932,7 +2263,7 @@ js-tokens@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" -js-yaml@~3.6.1: +js-yaml@^3.5.1, js-yaml@~3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" dependencies: @@ -1951,6 +2282,12 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -1973,6 +2310,10 @@ jsonfile@^2.1.0: optionalDependencies: graceful-fs "^4.1.6" +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + jsonpointer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" @@ -2130,6 +2471,13 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + liftoff@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385" @@ -2203,11 +2551,15 @@ lodash.pick@^4.2.1: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" +lodash.pickby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" + lodash@^3.10.1, lodash@^3.8.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.0.1, lodash@^4.14.0, lodash@^4.2.0, lodash@^4.5.0: +lodash@^4.0.0, lodash@^4.0.1, lodash@^4.14.0, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0: version "4.16.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.4.tgz#01ce306b9bad1319f2a5528674f88297aeb70127" @@ -2410,6 +2762,10 @@ ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + mz@^2.3.1: version "2.4.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.4.0.tgz#987ba9624d89395388c37cb4741e2caf4dd13b1a" @@ -2422,6 +2778,10 @@ nan@^2.3.0, nan@^2.3.2: version "2.4.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + ncp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" @@ -2620,6 +2980,10 @@ once@~1.3.0, once@~1.3.3: dependencies: wrappy "1" +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + openurl@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.0.tgz#e2f2189d999c04823201f083f0f1a7cd8903187a" @@ -2638,6 +3002,17 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" @@ -2728,6 +3103,10 @@ path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + path-root-regex@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" @@ -2778,6 +3157,10 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + portscanner@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/portscanner/-/portscanner-1.0.0.tgz#3b5cfe393828b5160abc600e6270ebc2f1590558" @@ -2989,6 +3372,10 @@ postcss-zindex@^2.0.1: postcss "^5.0.4" uniqs "^2.0.0" +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + prepend-http@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -3005,7 +3392,7 @@ process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" -progress@~1.1.8: +progress@^1.1.8, progress@~1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" @@ -3148,6 +3535,14 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -3300,6 +3695,13 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-uncached@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.2.tgz#67dad3b733089e77030124678a459589faf6a7ec" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + requires-port@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -3311,6 +3713,10 @@ resolve-dir@^0.1.0: expand-tilde "^1.2.2" global-modules "^0.2.3" +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolve@^1.1.6, resolve@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -3322,6 +3728,13 @@ resp-modifier@6.0.2: debug "^2.2.0" minimatch "^3.0.2" +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + retry@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.0.tgz#649e15ca408422d98318161935e7f7d652d435dd" @@ -3354,6 +3767,16 @@ rsvp@^3.0.13, rsvp@^3.0.18: version "3.3.3" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813" +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + rx@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" @@ -3448,6 +3871,10 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" +shelljs@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + sigmund@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -3460,6 +3887,10 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + sntp@1.x.x: version "1.0.9" resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" @@ -3635,6 +4066,13 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + stringstream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -3651,13 +4089,17 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" dependencies: get-stdin "^4.0.1" -strip-json-comments@~1.0.4: +strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" @@ -3709,6 +4151,17 @@ systemjs@^0.19.39, systemjs@0.19.39: dependencies: when "^3.7.5" +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + tar-fs@^1.13.0: version "1.14.0" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.14.0.tgz#f99cc074bf33bed21cd921a21720797bb18e6c96" @@ -3747,6 +4200,10 @@ tar@^2.0.0, tar@~2.2.0, tar@~2.2.1: fstream "^1.0.2" inherits "2" +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + tfunk@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/tfunk/-/tfunk-3.0.2.tgz#327ebc6176af2680c6cd0d6d22297c79d7f96efd" @@ -3770,6 +4227,10 @@ throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + timers-ext@0.1: version "0.1.0" resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.0.tgz#00345a2ca93089d1251322054389d263e27b77e2" @@ -3817,6 +4278,10 @@ trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" +tryit@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.2.tgz#c196b0073e6b1c595d93c9c830855b7acc32a453" + tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" @@ -3825,6 +4290,12 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.3.tgz#3da382f670f25ded78d7b3d1792119bca0b7132d" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + type-is@~1.6.13: version "1.6.13" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.13.tgz#6e83ba7bc30cd33a7bb0b7fb00737a2085bf9d08" @@ -3891,6 +4362,12 @@ user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + useragent@^2.1.9: version "2.1.9" resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.9.tgz#4dba2bc4dad1875777ab15de3ff8098b475000b7" @@ -3988,6 +4465,10 @@ wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -4002,6 +4483,12 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + ws@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ws/-/ws-1.0.1.tgz#7d0b2a2e58cddd819039c29c9de65045e1b310e9" From e5d1561bcdc7f94b8761a9318ed9ba1588acd376 Mon Sep 17 00:00:00 2001 From: Alfredo Matos Date: Tue, 1 Nov 2016 11:07:41 +0000 Subject: [PATCH 457/593] Force xhtml on span tags --- src/scripts/core.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/core.js b/src/scripts/core.js index 4f4428be..eda69d16 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -971,7 +971,8 @@ 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] + ''; From c066006520a56c4290b27f482a16a775751f9c8e Mon Sep 17 00:00:00 2001 From: Sergey Kovalyov Date: Thu, 19 Jan 2017 14:39:20 +0000 Subject: [PATCH 458/593] Enable drawing donut charts using filled shapes * Add donutSolid option support. * Add solid donut charts examples. --- site/data/pages/examples.yml | 16 +++++++++ site/examples/example-donut-solid-chart.js | 9 +++++ .../example-gauge-donut-solid-chart.js | 10 ++++++ src/scripts/charts/pie.js | 34 ++++++++++++++++--- src/styles/chartist.scss | 2 +- src/styles/settings/_chartist-settings.scss | 1 + 6 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 site/examples/example-donut-solid-chart.js create mode 100644 site/examples/example-gauge-donut-solid-chart.js diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 04b7a27e..9d487a40 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -256,3 +256,19 @@ sections: intro: > Although it'd be also possible to achieve this animation with CSS, with some minor suboptimal things, here's an example of how to animate donut charts using Chartist.Svg.animate and SMIL. + + - type: live-example + data: + title: Donut chart using fill rather than stroke + level: 4 + id: example-donut-solid-chart + classes: ct-golden-section ct-negative-labels + intro: This pie chart uses donut and donutSolid to draw a donut chart. + + - type: live-example + data: + title: Gauge chart using fill rather than stroke + level: 4 + id: example-gauge-donut-solid-chart + classes: ct-golden-section ct-negative-labels + intro: This pie chart uses total, startAngle, donut and donutSolid to draw a gauge chart. diff --git a/site/examples/example-donut-solid-chart.js b/site/examples/example-donut-solid-chart.js new file mode 100644 index 00000000..57b2a176 --- /dev/null +++ b/site/examples/example-donut-solid-chart.js @@ -0,0 +1,9 @@ +new Chartist.Pie('.ct-chart', { + series: [20, 10, 30, 40] +}, { + donut: true, + donutWidth: 60, + donutSolid: true, + startAngle: 270, + showLabel: true +}); diff --git a/site/examples/example-gauge-donut-solid-chart.js b/site/examples/example-gauge-donut-solid-chart.js new file mode 100644 index 00000000..735303ff --- /dev/null +++ b/site/examples/example-gauge-donut-solid-chart.js @@ -0,0 +1,10 @@ +new Chartist.Pie('.ct-chart', { + series: [20, 10, 30, 40] +}, { + donut: true, + donutWidth: 60, + donutSolid: true, + startAngle: 270, + total: 200, + showLabel: true +}); diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 6a80cffb..ebec55b0 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -26,6 +26,7 @@ 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. @@ -34,6 +35,8 @@ 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, @@ -109,15 +112,17 @@ // 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 @@ -178,21 +183,40 @@ 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({ @@ -201,7 +225,7 @@ }); // If this is a donut, we add the stroke-width as style attribute - if(options.donut) { + if(options.donut && !options.donutSolid) { pathElement.attr({ 'style': 'stroke-width: ' + donutWidth.value + 'px' }); diff --git a/src/styles/chartist.scss b/src/styles/chartist.scss index e3caaa6b..e5c6b420 100644 --- a/src/styles/chartist.scss +++ b/src/styles/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/src/styles/settings/_chartist-settings.scss b/src/styles/settings/_chartist-settings.scss index 4d0370eb..def297ca 100644 --- a/src/styles/settings/_chartist-settings.scss +++ b/src/styles/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; From 4e36bbaea3a8204a147a119ca6135c1be838070b Mon Sep 17 00:00:00 2001 From: Nick Bartlett Date: Tue, 21 Mar 2017 03:27:59 -0400 Subject: [PATCH 459/593] :bug: fix grammar, typo --- site/data/pages/index.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 3763ee48..27a3a7f8 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -302,4 +302,4 @@ sections: side-notes: - type: text data: - text: With the clear separation of concerns within Chartist.js you're able to style your charts with CSS in @media queries. However, sometimes it requires to also control the behaviour of your charts depending on the media. For this purpose Chartist.js provides you with a simple configuration override mechanism based on media queries. + text: With the clear separation of concerns within Chartist.js, you're able to style your charts with CSS in @media queries. However, sometimes you also need to conditionally control the behavior of your charts. For this purpose, Chartist.js provides you with a simple configuration override mechanism based on media queries. From f12dbc4b349fa670be137f02d1ca21e192aa1bd5 Mon Sep 17 00:00:00 2001 From: Sergey Kovalyov Date: Tue, 21 Mar 2017 11:30:53 +0100 Subject: [PATCH 460/593] Refactor conditional to else if --- src/scripts/charts/pie.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index ebec55b0..62dc9aba 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -195,14 +195,12 @@ // 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); - } + } 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 From 3857a194b101eb5268469df3c0be6120c40927a3 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Wed, 5 Apr 2017 11:40:18 +0200 Subject: [PATCH 461/593] Use HTML DOM style Property instead of adding inline styles to elements --- src/scripts/charts/pie.js | 4 +--- src/scripts/core.js | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 62dc9aba..9d53861e 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -224,9 +224,7 @@ // If this is a donut, we add the stroke-width as style attribute if(options.donut && !options.donutSolid) { - pathElement.attr({ - 'style': 'stroke-width: ' + donutWidth.value + 'px' - }); + pathElement._node.style.strokeWidth = donutWidth.value + 'px'; } // Fire off draw event diff --git a/src/scripts/core.js b/src/scripts/core.js index eda69d16..fa3a1f79 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -315,9 +315,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); @@ -971,11 +972,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;' From e2ee06153f099b548530ef517a247fc0dc978cb8 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Tue, 11 Apr 2017 11:41:07 +0200 Subject: [PATCH 462/593] Version bump and latest dist --- CHANGELOG.md | 5 ++ dist/chartist.css | 30 +++++------ dist/chartist.css.map | 2 +- dist/chartist.js | 61 +++++++++++++++------- dist/chartist.min.css | 2 +- dist/chartist.min.js | 8 +-- dist/chartist.min.js.map | 2 +- dist/scss/chartist.scss | 2 +- dist/scss/settings/_chartist-settings.scss | 1 + package.json | 2 +- 10 files changed, 72 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8efd792f..3e8b2348 100644 --- a/CHANGELOG.md +++ b/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/dist/chartist.css b/dist/chartist.css index 35f27d8f..bb19a807 100644 --- a/dist/chartist.css +++ b/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/dist/chartist.css.map b/dist/chartist.css.map index cee2d405..106c0763 100644 --- a/dist/chartist.css.map +++ b/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/dist/chartist.js b/dist/chartist.js index 050d0a62..322d8ad7 100644 --- a/dist/chartist.js +++ b/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/dist/chartist.min.css b/dist/chartist.min.css index 9f9b908e..6a23d470 100644 --- a/dist/chartist.min.css +++ b/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/dist/chartist.min.js b/dist/chartist.min.js index e0fec43c..b54d35a0 100644 --- a/dist/chartist.min.js +++ b/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/dist/chartist.min.js.map b/dist/chartist.min.js.map index 7006d742..bdcce040 100644 --- a/dist/chartist.min.js.map +++ b/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":";;;;;;;CAAC,SAAUA,EAAMC,GACO,kBAAXC,SAAyBA,OAAOC,IAEzCD,OAAO,cAAgB,WACrB,MAAQF,GAAe,SAAIC,MAEF,gBAAXG,SAAuBA,OAAOC,QAI9CD,OAAOC,QAAUJ,IAEjBD,EAAe,SAAIC,KAErBK,KAAM,WAaR,GAAIC,IACFC,QAAS,SAy2IX,OAt2IC,UAAUC,EAAQC,EAAUH,GAC3B,YAQAA,GAASI,YACPC,IAAK,6BACLC,MAAO,gCACPC,MAAO,+BACPC,MAAO,+BACPC,GAAI,6CAUNT,EAASU,KAAO,SAAUC,GACxB,MAAOA,IAUTX,EAASY,cAAgB,SAAUD,GAEjC,MAAOE,QAAOC,aAAa,GAAKH,EAAI,KAWtCX,EAASe,OAAS,SAAUC,GAC1B,GAAIC,GAAGC,EAAQC,CAGf,KAFAH,EAASA,MAEJC,EAAI,EAAGA,EAAIG,UAAUC,OAAQJ,IAAK,CACrCC,EAASE,UAAUH,EACnB,KAAK,GAAIK,KAAQJ,GACfC,EAAaD,EAAOI,GACM,gBAAfH,IAA0C,OAAfA,GAAyBA,YAAsBI,OAGnFP,EAAOM,GAAQH,EAFfH,EAAOM,GAAQtB,EAASe,OAAOC,EAAOM,GAAOH,GAOnD,MAAOH,IAYThB,EAASwB,WAAa,SAASC,EAAKC,EAAQC,GAC1C,MAAOF,GAAIG,QAAQ,GAAIC,QAAOH,EAAQ,KAAMC,IAW9C3B,EAAS8B,WAAa,SAASC,EAAOC,GAKpC,MAJoB,gBAAVD,KACRA,GAAgBC,GAGXD,GAUT/B,EAASiC,SAAW,SAASC,GAC3B,GAAqB,gBAAVA,GAAoB,CAC7B,GAAIC,GAAQ,kBAAoBC,KAAKF,EACrC,QACEH,OAASI,EAAM,GACfH,KAAMG,EAAM,IAAME,QAGtB,OAASN,MAAOG,IAUlBlC,EAASsC,cAAgB,SAASC,GAChC,MAAOA,aAAiBC,MAAOD,EAAQpC,EAASmC,cAAcC,IAUhEvC,EAASyC,MAAQ,SAASpB,GACxB,MAAOE,OAAMmB,MAAM,KAAM,GAAInB,OAAMF,KAWrCrB,EAAS2C,IAAM,SAASC,EAAUC,GAChC,MAAOD,IAAYC,EAAUA,EAAU,IAUzC7C,EAAS8C,YAAc,SAASC,GAC9B,MAAO,UAASC,GACd,MAAOA,GAAMD,IAWjB/C,EAASiD,OAAS,SAASC,GACzB,MAAO,UAASF,GACd,MAAOA,GAAME,IAYjBlD,EAASmD,UAAY,SAASC,EAAKC,GACjC,GAAIC,MACAjC,EAASkC,KAAKC,IAAId,MAAM,KAAMU,EAAIK,IAAI,SAASC,GAC7C,MAAOA,GAAErC,SAWf,OARArB,GAASyC,MAAMpB,GAAQsC,QAAQ,SAASD,EAAGE,GACzC,GAAIC,GAAOT,EAAIK,IAAI,SAASC,GAC1B,MAAOA,GAAEE,IAGXN,GAAOM,GAASP,EAAGX,MAAM,KAAMmB,KAG1BP,GAWTtD,EAAS8D,mBAAqB,SAAS/B,EAAOgC,GAC5C,GAAIC,GAAYT,KAAKU,IAAI,GAAIF,GAAU/D,EAASgE,UAChD,OAAOT,MAAKW,MAAMnC,EAAQiC,GAAaA,GASzChE,EAASgE,UAAY,EAQrBhE,EAASmE,aACPC,IAAK,QACLC,IAAK,OACLC,IAAK,OACLC,IAAK,SACLC,IAAM,UAWRxE,EAASyE,UAAY,SAASC,GAC5B,MAAY,QAATA,GAA0BrC,SAATqC,EACXA,GACiB,gBAATA,GACfA,EAAO,GAAGA,EACc,gBAATA,KACfA,EAAOC,KAAKC,WAAWF,KAAMA,KAGxBG,OAAOC,KAAK9E,EAASmE,aAAaY,OAAO,SAASzB,EAAQ0B,GAC/D,MAAOhF,GAASwB,WAAW8B,EAAQ0B,EAAKhF,EAASmE,YAAYa,KAC5DN,KAUL1E,EAASiF,YAAc,SAASP,GAC9B,GAAmB,gBAATA,GACR,MAAOA,EAGTA,GAAOG,OAAOC,KAAK9E,EAASmE,aAAaY,OAAO,SAASzB,EAAQ0B,GAC/D,MAAOhF,GAASwB,WAAW8B,EAAQtD,EAASmE,YAAYa,GAAMA,IAC7DN,EAEH,KACEA,EAAOC,KAAKO,MAAMR,GAClBA,EAAqBrC,SAAdqC,EAAKA,KAAqBA,EAAKA,KAAOA,EAC7C,MAAMhB,IAER,MAAOgB,IAaT1E,EAASmF,UAAY,SAAUC,EAAWC,EAAOC,EAAQC,GACvD,GAAIlF,EAyBJ,OAvBAgF,GAAQA,GAAS,OACjBC,EAASA,GAAU,OAInB/D,MAAMiE,UAAUC,MAAMC,KAAKN,EAAUO,iBAAiB,QAAQC,OAAO,SAAkCvF,GACrG,MAAOA,GAAIwF,eAAe7F,EAASI,WAAWE,MAAO,QACpDqD,QAAQ,SAA+BtD,GACxC+E,EAAUU,YAAYzF,KAIxBA,EAAM,GAAIL,GAAS+F,IAAI,OAAOC,MAC5BX,MAAOA,EACPC,OAAQA,IACPW,SAASV,GAEZlF,EAAI6F,MAAMC,MAAMd,MAAQA,EACxBhF,EAAI6F,MAAMC,MAAMb,OAASA,EAGzBF,EAAUgB,YAAY/F,EAAI6F,OAEnB7F,GASTL,EAASqG,cAAgB,SAAS3B,EAAM4B,EAASC,GAC/C,GAAIC,GACAC,GACFC,IAAKhC,EACLiC,cAmCF,OA/BAF,GAAOE,WAAWC,OAAS5G,EAAS6G,cAClCD,OAAQlC,EAAKkC,YACZN,EAASC,GAQVC,EAJEC,EAAOE,WAAWC,OAAOE,MAAM,SAAS/E,GACxC,MAAOA,aAAiBR,SAGbgC,KAAKC,IAAId,MAAM,KAAM+D,EAAOE,WAAWC,OAAOnD,IAAI,SAASmD,GACtE,MAAOA,GAAOvF,UAIHoF,EAAOE,WAAWC,OAAOvF,OAGxCoF,EAAOE,WAAWI,QAAUrC,EAAKqC,YAActB,QAE/ClE,MAAMiE,UAAUwB,KAAKtE,MACnB+D,EAAOE,WAAWI,OAClB/G,EAASyC,MAAMc,KAAKC,IAAI,EAAGgD,EAAaC,EAAOE,WAAWI,OAAO1F,SAASoC,IAAI,WAC5E,MAAO,MAIR6C,GACDtG,EAASiH,YAAYR,EAAOE,YAGvBF,GAUTzG,EAASkH,gBAAkB,SAASC,EAAQC,GAC1C,MAAkB,QAAXD,GACa,gBAAXA,IACPA,EAAOE,eAAeD,IAS1BpH,EAASsH,gBAAkB,SAASvF,GAClC,MAAiB,QAAVA,GACKM,SAAVN,GACkB,gBAAVA,IAAsBwF,MAAMxF,IASxC/B,EAASiH,YAAc,SAASvC,GAC9BA,EAAKqC,OAAOT,UACZ5B,EAAKkC,OAAON,SACZ,KAAK,GAAIrF,GAAI,EAAGA,EAAIyD,EAAKkC,OAAOvF,OAAQJ,IACR,gBAApByD,GAAKkC,OAAO3F,IAA4CoB,SAAxBqC,EAAKkC,OAAO3F,GAAGyD,KACvDA,EAAKkC,OAAO3F,GAAGyD,KAAK4B,UACZ5B,EAAKkC,OAAO3F,YAAcM,QAClCmD,EAAKkC,OAAO3F,GAAGqF,WAcrBtG,EAAS6G,aAAe,SAASnC,EAAM4B,EAASC,GAG9C,QAASiB,GAAiBzF,GACxB,GAAG/B,EAASkH,gBAAgBnF,EAAO,SAEjC,MAAOyF,GAAiBzF,EAAMA,MACzB,IAAG/B,EAASkH,gBAAgBnF,EAAO,QAExC,MAAOyF,GAAiBzF,EAAM2C,KACzB,IAAG3C,YAAiBR,OAEzB,MAAOQ,GAAM0B,IAAI+D,EACZ,KAAGxH,EAASsH,gBAAgBvF,GAA5B,CAML,GAAGwE,EAAO,CACR,GAAIkB,KAcJ,OAToB,gBAAVlB,GACRkB,EAAWlB,GAASvG,EAAS0H,qBAAqB3F,GAElD0F,EAAWE,EAAI3H,EAAS0H,qBAAqB3F,GAG/C0F,EAAWG,EAAI7F,EAAMsF,eAAe,KAAOrH,EAAS0H,qBAAqB3F,EAAM6F,GAAKH,EAAWG,EAC/FH,EAAWE,EAAI5F,EAAMsF,eAAe,KAAOrH,EAAS0H,qBAAqB3F,EAAM4F,GAAKF,EAAWE,EAExFF,EAIP,MAAOzH,GAAS0H,qBAAqB3F,IAK3C,MAAO2C,GAAKkC,OAAOnD,IAAI+D,IAWzBxH,EAAS6H,iBAAmB,SAASC,EAASC,GAG5C,MAFAA,GAAWA,GAAY,EAEG,gBAAZD,IACZE,IAAKF,EACLG,MAAOH,EACPI,OAAQJ,EACRK,KAAML,IAENE,IAA4B,gBAAhBF,GAAQE,IAAmBF,EAAQE,IAAMD,EACrDE,MAAgC,gBAAlBH,GAAQG,MAAqBH,EAAQG,MAAQF,EAC3DG,OAAkC,gBAAnBJ,GAAQI,OAAsBJ,EAAQI,OAASH,EAC9DI,KAA8B,gBAAjBL,GAAQK,KAAoBL,EAAQK,KAAOJ,IAI5D/H,EAASoI,YAAc,SAASxB,EAAQhD,GACtC,GAAI7B,GAAQ6E,EAAOlC,KAAOkC,EAAOlC,KAAKd,GAASgD,EAAOhD,EACtD,OAAO7B,GAAQA,EAAMsG,KAAOhG,QAU9BrC,EAASsI,iBAAmB,SAAUvG,GACpC,MAAOwB,MAAKgF,MAAMhF,KAAKiF,IAAIjF,KAAKkF,IAAI1G,IAAUwB,KAAKmF,OAYrD1I,EAAS2I,cAAgB,SAAUC,EAAYvH,EAAQwH,GACrD,MAAOxH,GAASwH,EAAOC,MAAQF,GAWjC5I,EAAS+I,mBAAqB,SAAU1I,EAAK2I,GAC3C,MAAOzF,MAAKC,KAAKxD,EAASiC,SAAS+G,EAAQ1D,QAAQvD,OAAS1B,EAAIiF,WAAa0D,EAAQC,aAAajB,IAAOgB,EAAQC,aAAaf,QAAUc,EAAQE,MAAMC,OAAQ,IAYhKnJ,EAASoJ,WAAa,SAAU1E,EAAMsE,EAASK,GAY7C,QAASC,GAAiB5E,GACxB,GAAYrC,SAATqC,EAEI,GAAGA,YAAgBnD,OACxB,IAAK,GAAIN,GAAI,EAAGA,EAAIyD,EAAKrD,OAAQJ,IAC/BqI,EAAiB5E,EAAKzD,QAEnB,CACL,GAAIc,GAAQsH,GAAa3E,EAAK2E,IAAc3E,CAExC6E,IAAYxH,EAAQyH,EAAQC,OAC9BD,EAAQC,KAAO1H,GAGb2H,GAAW3H,EAAQyH,EAAQG,MAC7BH,EAAQG,IAAM5H,IAzBpBiH,EAAUhJ,EAASe,UAAWiI,EAASK,EAAYL,EAAQ,OAASK,EAAUO,kBAE9E,IAAIJ,IACAC,KAAuBpH,SAAjB2G,EAAQS,MAAsBI,OAAOC,WAAad,EAAQS,KAChEE,IAAqBtH,SAAhB2G,EAAQW,IAAoBE,OAAOC,WAAad,EAAQW,KAE7DJ,EAA4BlH,SAAjB2G,EAAQS,KACnBC,EAA0BrH,SAAhB2G,EAAQW,GAuDtB,QA/BGJ,GAAYG,IACbJ,EAAiB5E,IAMfsE,EAAQe,gBAA6C,IAA3Bf,EAAQe,kBACpCP,EAAQC,KAAOlG,KAAKC,IAAIwF,EAAQe,eAAgBP,EAAQC,MACxDD,EAAQG,IAAMpG,KAAKyG,IAAIhB,EAAQe,eAAgBP,EAAQG,MAKrDH,EAAQC,MAAQD,EAAQG,MAEN,IAAhBH,EAAQG,IACVH,EAAQC,KAAO,EACND,EAAQG,IAAM,EAEvBH,EAAQC,KAAO,EACND,EAAQC,KAAO,EAExBD,EAAQG,IAAM,GAGdH,EAAQC,KAAO,EACfD,EAAQG,IAAM,IAIXH,GAUTxJ,EAASiK,UAAY,SAASlI,GAC5B,MAAiB,QAAVA,GAAyBmI,SAASnI,IAU3C/B,EAASmK,gBAAkB,SAASpI,GAClC,OAAQA,GAAmB,IAAVA,GAUnB/B,EAAS0H,qBAAuB,SAAS3F,GACvC,MAAO/B,GAASiK,UAAUlI,IAAUA,EAAQM,QAS9CrC,EAASoK,aAAe,SAASrI,GAC/B,MAAwB,gBAAVA,KAAuB,KAAOA,IAAS,KAAOA,KAY9D/B,EAASqK,cAAgB,SAAStI,EAAOsH,GACvC,MAAGrJ,GAASoK,aAAarI,GAChB/B,EAAS0H,qBAAqB3F,EAAMsH,GAAa,MAEjDrJ,EAAS0H,qBAAqB3F,IAWzC/B,EAASsK,IAAM,SAAStH,GAKtB,QAASuH,GAAIC,EAAGC,GACd,MAAID,GAAIC,IAAM,EACLA,EAEAF,EAAIE,EAAGD,EAAIC,GAItB,QAASC,GAAE9C,GACT,MAAOA,GAAIA,EAAI,EAbjB,GAAW,IAAR5E,EACD,MAAOA,EAeT,IAAoB2H,GAAhBC,EAAK,EAAGC,EAAK,CACjB,IAAI7H,EAAM,IAAM,EACd,MAAO,EAGT,GACE4H,GAAKF,EAAEE,GAAM5H,EACb6H,EAAKH,EAAEA,EAAEG,IAAO7H,EAChB2H,EAAUJ,EAAIhH,KAAKkF,IAAImC,EAAKC,GAAK7H,SACd,IAAZ2H,EAET,OAAOA,IAaT3K,EAAS8K,UAAY,SAAUlC,EAAYY,EAASuB,EAAeC,GAuDjE,QAASC,GAAclJ,EAAOmJ,GAK5B,MAHInJ,MAAWA,GAASmJ,KACvBnJ,GAAU,GAAKmJ,EAAY,EAAIC,GAAWA,IAEpCpJ,EA3DT,GAAId,GAEFmK,EACAC,EAFAC,EAAsB,EAGtBzC,GACEY,KAAMD,EAAQC,KACdE,IAAKH,EAAQG,IAGjBd,GAAO0C,WAAa1C,EAAOY,KAAOZ,EAAOc,IACzCd,EAAO2C,IAAMxL,EAASsI,iBAAiBO,EAAO0C,YAC9C1C,EAAO4C,KAAOlI,KAAKU,IAAI,GAAI4E,EAAO2C,KAClC3C,EAAOmB,IAAMzG,KAAKgF,MAAMM,EAAOc,IAAMd,EAAO4C,MAAQ5C,EAAO4C,KAC3D5C,EAAOrF,IAAMD,KAAKmI,KAAK7C,EAAOY,KAAOZ,EAAO4C,MAAQ5C,EAAO4C,KAC3D5C,EAAOC,MAAQD,EAAOrF,IAAMqF,EAAOmB,IACnCnB,EAAO8C,cAAgBpI,KAAKW,MAAM2E,EAAOC,MAAQD,EAAO4C,KAIxD,IAAIpK,GAASrB,EAAS2I,cAAcC,EAAYC,EAAO4C,KAAM5C,GACzD+C,EAAUvK,EAAS0J,EACnBc,EAAiBb,EAAchL,EAASsK,IAAIzB,EAAOC,OAAS,CAGhE,IAAGkC,GAAehL,EAAS2I,cAAcC,EAAY,EAAGC,IAAWkC,EACjElC,EAAO4C,KAAO,MACT,IAAGT,GAAea,EAAiBhD,EAAO4C,MAAQzL,EAAS2I,cAAcC,EAAYiD,EAAgBhD,IAAWkC,EAIrHlC,EAAO4C,KAAOI,MAGd,QAAa,CACX,GAAID,GAAW5L,EAAS2I,cAAcC,EAAYC,EAAO4C,KAAM5C,IAAWkC,EACxElC,EAAO4C,MAAQ,MACV,CAAA,GAAKG,KAAW5L,EAAS2I,cAAcC,EAAYC,EAAO4C,KAAO,EAAG5C,IAAWkC,GAOpF,KALA,IADAlC,EAAO4C,MAAQ,EACZT,GAAenC,EAAO4C,KAAO,IAAM,EAAG,CACvC5C,EAAO4C,MAAQ,CACf,QAMJ,GAAGH,IAAwB,IACzB,KAAM,IAAIQ,OAAM,sEAKtB,GAAIX,GAAU,SAad,KAZAtC,EAAO4C,KAAOlI,KAAKC,IAAIqF,EAAO4C,KAAMN,GAUpCC,EAASvC,EAAOmB,IAChBqB,EAASxC,EAAOrF,IACT4H,EAASvC,EAAO4C,MAAQ5C,EAAOc,KACrCyB,EAASH,EAAcG,EAAQvC,EAAO4C,KAEvC,MAAOJ,EAASxC,EAAO4C,MAAQ5C,EAAOY,MACrC4B,EAASJ,EAAcI,GAASxC,EAAO4C,KAExC5C,GAAOmB,IAAMoB,EACbvC,EAAOrF,IAAM6H,EACbxC,EAAOC,MAAQD,EAAOrF,IAAMqF,EAAOmB,GAEnC,IAAI+B,KACJ,KAAK9K,EAAI4H,EAAOmB,IAAK/I,GAAK4H,EAAOrF,IAAKvC,EAAIgK,EAAchK,EAAG4H,EAAO4C,MAAO,CACvE,GAAI1J,GAAQ/B,EAAS8D,mBAAmB7C,EACpCc,KAAUgK,EAAOA,EAAO1K,OAAS,IACnC0K,EAAO/E,KAAKjF,GAIhB,MADA8G,GAAOkD,OAASA,EACTlD,GAaT7I,EAASgM,iBAAmB,SAAUC,EAASC,EAASC,EAAQC,GAC9D,GAAIC,IAAkBD,EAAiB,IAAM7I,KAAK+I,GAAK,GAEvD,QACE1E,EAAGqE,EAAWE,EAAS5I,KAAKgJ,IAAIF,GAChC1E,EAAGuE,EAAWC,EAAS5I,KAAKiJ,IAAIH,KAapCrM,EAASyM,gBAAkB,SAAUpM,EAAK2I,EAAS0D,GACjD,GAAIC,MAAa3D,EAAQE,QAASF,EAAQ4D,OACtCC,EAAcF,EAAU3D,EAAQ4D,MAAMzD,OAAS,EAC/C2D,EAAcH,EAAU3D,EAAQE,MAAMC,OAAS,EAE/C9D,EAAQhF,EAAIgF,SAAWrF,EAASiC,SAAS+G,EAAQ3D,OAAOtD,OAAS,EACjEuD,EAASjF,EAAIiF,UAAYtF,EAASiC,SAAS+G,EAAQ1D,QAAQvD,OAAS,EACpEgL,EAAoB/M,EAAS6H,iBAAiBmB,EAAQC,aAAcyD,EAGxErH,GAAQ9B,KAAKC,IAAI6B,EAAOwH,EAAcE,EAAkB5E,KAAO4E,EAAkB9E,OACjF3C,EAAS/B,KAAKC,IAAI8B,EAAQwH,EAAcC,EAAkB/E,IAAM+E,EAAkB7E,OAElF,IAAI8E,IACFlF,QAASiF,EACT1H,MAAO,WACL,MAAOtF,MAAK8K,GAAK9K,KAAK6K,IAExBtF,OAAQ,WACN,MAAOvF,MAAKkN,GAAKlN,KAAKmN,IA2B1B,OAvBGP,IAC8B,UAA3B3D,EAAQE,MAAMiE,UAChBH,EAAUE,GAAKH,EAAkB/E,IAAM8E,EACvCE,EAAUC,GAAK1J,KAAKC,IAAI8B,EAASyH,EAAkB7E,OAAQ8E,EAAUE,GAAK,KAE1EF,EAAUE,GAAKH,EAAkB/E,IACjCgF,EAAUC,GAAK1J,KAAKC,IAAI8B,EAASyH,EAAkB7E,OAAS4E,EAAaE,EAAUE,GAAK,IAG3D,UAA3BlE,EAAQ4D,MAAMO,UAChBH,EAAUpC,GAAKmC,EAAkB5E,KAAO0E,EACxCG,EAAUnC,GAAKtH,KAAKC,IAAI6B,EAAQ0H,EAAkB9E,MAAO+E,EAAUpC,GAAK,KAExEoC,EAAUpC,GAAKmC,EAAkB5E,KACjC6E,EAAUnC,GAAKtH,KAAKC,IAAI6B,EAAQ0H,EAAkB9E,MAAQ4E,EAAaG,EAAUpC,GAAK,MAGxFoC,EAAUpC,GAAKmC,EAAkB5E,KACjC6E,EAAUnC,GAAKtH,KAAKC,IAAI6B,EAAQ0H,EAAkB9E,MAAO+E,EAAUpC,GAAK,GACxEoC,EAAUE,GAAKH,EAAkB/E,IACjCgF,EAAUC,GAAK1J,KAAKC,IAAI8B,EAASyH,EAAkB7E,OAAQ8E,EAAUE,GAAK,IAGrEF,GAgBThN,EAASoN,WAAa,SAASD,EAAUvJ,EAAOyJ,EAAMlE,EAAQ9H,EAAQiM,EAAOC,EAASC,GACpF,GAAIC,KACJA,GAAeJ,EAAKK,MAAMC,IAAM,KAAOR,EACvCM,EAAeJ,EAAKK,MAAMC,IAAM,KAAOR,EACvCM,EAAeJ,EAAKO,aAAaD,IAAM,KAAOxE,EAC9CsE,EAAeJ,EAAKO,aAAaD,IAAM,KAAOxE,EAAS9H,CAEvD,IAAIwM,GAAcP,EAAMQ,KAAK,OAAQL,EAAgBF,EAAQQ,KAAK,KAGlEP,GAAaQ,KAAK,OAChBhO,EAASe,QACPkN,KAAM,OACNZ,KAAMA,EACNzJ,MAAOA,EACP0J,MAAOA,EACPY,QAASL,GACRJ,KAaPzN,EAASmO,qBAAuB,SAAUC,EAAWpB,EAAWzH,EAAWiI,GACzE,GAAIa,GAAiBD,EAAUN,KAAK,QAChClG,EAAGoF,EAAUpC,GACbjD,EAAGqF,EAAUE,GACb7H,MAAO2H,EAAU3H,QACjBC,OAAQ0H,EAAU1H,UACjBC,GAAW,EAGdiI,GAAaQ,KAAK,QAChBC,KAAM,iBACNX,MAAOc,EACPF,QAASG,KAoBfrO,EAASsO,YAAc,SAASnB,EAAU9L,EAAQuC,EAAOmD,EAAQsG,EAAMkB,EAAYC,EAAalB,EAAOC,EAASkB,EAAkBjB,GAChI,GAAIkB,GACAjB,IAOJ,IALAA,EAAeJ,EAAKK,MAAMC,KAAOR,EAAWqB,EAAYnB,EAAKK,MAAMC,KACnEF,EAAeJ,EAAKO,aAAaD,KAAOa,EAAYnB,EAAKO,aAAaD,KACtEF,EAAeJ,EAAKK,MAAMiB,KAAOtN,EACjCoM,EAAeJ,EAAKO,aAAae,KAAOpL,KAAKC,IAAI,EAAG+K,EAAa,IAE9DE,EAAkB,CAGnB,GAAIG,GAAUzO,EAAS0O,cAAc,OACrCD,GAAQrJ,UAAYgI,EAAQQ,KAAK,KACjCa,EAAQE,aAAa,QAAS9O,EAASI,WAAWG,OAClDqO,EAAQG,UAAYhI,EAAOnD,GAC3BgL,EAAQzI,MAAMkH,EAAKK,MAAMiB,KAAOpL,KAAKW,MAAMuJ,EAAeJ,EAAKK,MAAMiB,MAAQ,KAC7EC,EAAQzI,MAAMkH,EAAKO,aAAae,KAAOpL,KAAKW,MAAMuJ,EAAeJ,EAAKO,aAAae,MAAQ,KAE3FD,EAAepB,EAAM0B,cAAcJ,EAAS5O,EAASe,QACnDoF,MAAO,sBACNsH,QAEHiB,GAAepB,EAAMQ,KAAK,OAAQL,EAAgBF,EAAQQ,KAAK,MAAMkB,KAAKlI,EAAOnD,GAGnF4J,GAAaQ,KAAK,OAAQhO,EAASe,QACjCkN,KAAM,QACNZ,KAAMA,EACNzJ,MAAOA,EACP0J,MAAOA,EACPY,QAASQ,EACTO,KAAMlI,EAAOnD,IACZ6J,KAYLzN,EAASkP,gBAAkB,SAAStI,EAAQoC,EAAShE,GACnD,GAAG4B,EAAOuI,MAAQnG,EAAQpC,QAAUoC,EAAQpC,OAAOA,EAAOuI,MAAO,CAC/D,GAAIC,GAAgBpG,EAAQpC,OAAOA,EAAOuI,KAC1C,OAAOC,GAAc/H,eAAerC,GAAOoK,EAAcpK,GAAOgE,EAAQhE,GAExE,MAAOgE,GAAQhE,IAanBhF,EAASqP,gBAAkB,SAAUrG,EAASsG,EAAmB9B,GAM/D,QAAS+B,GAAqBC,GAC5B,GAAIC,GAAkBC,CAGtB,IAFAA,EAAiB1P,EAASe,UAAW4O,GAEjCL,EACF,IAAKrO,EAAI,EAAGA,EAAIqO,EAAkBjO,OAAQJ,IAAK,CAC7C,GAAI2O,GAAM1P,EAAO2P,WAAWP,EAAkBrO,GAAG,GAC7C2O,GAAIE,UACNJ,EAAiB1P,EAASe,OAAO2O,EAAgBJ,EAAkBrO,GAAG,KAKzEuM,GAAgBgC,GACjBhC,EAAaQ,KAAK,kBAChByB,gBAAiBA,EACjBC,eAAgBA,IAKtB,QAASK,KACPC,EAAoBrM,QAAQ,SAASiM,GACnCA,EAAIK,eAAeV,KA5BvB,GACEG,GAEAzO,EAHE0O,EAAc3P,EAASe,UAAWiI,GAEpCgH,IA8BF,KAAK9P,EAAO2P,WACV,KAAM,iEACD,IAAIP,EAET,IAAKrO,EAAI,EAAGA,EAAIqO,EAAkBjO,OAAQJ,IAAK,CAC7C,GAAI2O,GAAM1P,EAAO2P,WAAWP,EAAkBrO,GAAG,GACjD2O,GAAIM,YAAYX,GAChBS,EAAoBhJ,KAAK4I,GAM7B,MAFAL,MAGEQ,0BAA2BA,EAC3BI,kBAAmB,WACjB,MAAOnQ,GAASe,UAAW2O,MA8BjC1P,EAASoQ,kBAAoB,SAASC,EAAiBC,EAAWtH,GAChE,GAAIuH,IACFC,aAAa,EACbC,WAAW,EAGbzH,GAAUhJ,EAASe,UAAWwP,EAAgBvH,EAK9C,KAAI,GAHA0H,MACAC,GAAO,EAEH1P,EAAI,EAAGA,EAAIoP,EAAgBhP,OAAQJ,GAAK,EAEQoB,SAAnDrC,EAASqK,cAAciG,EAAUrP,EAAI,GAAGc,OAErCiH,EAAQyH,YACVE,GAAO,IAGN3H,EAAQwH,aAAevP,GAAK,GAAKoP,EAAgBpP,IAAMoP,EAAgBpP,EAAE,KAE1E0P,GAAO,GAKNA,IACDD,EAAS1J,MACPqJ,mBACAC,eAGFK,GAAO,GAITD,EAASA,EAASrP,OAAS,GAAGgP,gBAAgBrJ,KAAKqJ,EAAgBpP,GAAIoP,EAAgBpP,EAAI,IAC3FyP,EAASA,EAASrP,OAAS,GAAGiP,UAAUtJ,KAAKsJ,EAAUrP,EAAI,IAI/D,OAAOyP,KAETxQ,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEAA,GAAS4Q,iBAmBT5Q,EAAS4Q,cAAcC,KAAO,SAAS7H,GACrC,GAAIuH,IACFE,WAAW,EAGb,OADAzH,GAAUhJ,EAASe,UAAWwP,EAAgBvH,GACvC,SAAcqH,EAAiBC,GAIpC,IAAI,GAHAQ,GAAO,GAAI9Q,GAAS+F,IAAIgL,KACxBJ,GAAO,EAEH1P,EAAI,EAAGA,EAAIoP,EAAgBhP,OAAQJ,GAAK,EAAG,CACjD,GAAI+P,GAAQX,EAAgBpP,GACxBgQ,EAAQZ,EAAgBpP,EAAI,GAC5BiQ,EAAWZ,EAAUrP,EAAI,EAEiBoB,UAA3CrC,EAASqK,cAAc6G,EAASnP,QAE9B4O,EACDG,EAAKK,KAAKH,EAAOC,GAAO,EAAOC,GAE/BJ,EAAKM,KAAKJ,EAAOC,GAAO,EAAOC,GAGjCP,GAAO,GACE3H,EAAQyH,YACjBE,GAAO,GAIX,MAAOG,KA2BX9Q,EAAS4Q,cAAcS,OAAS,SAASrI,GACvC,GAAIuH,IACF5F,QAAS,EACT8F,WAAW,EAEbzH,GAAUhJ,EAASe,UAAWwP,EAAgBvH,EAE9C,IAAIsI,GAAI,EAAI/N,KAAKC,IAAI,EAAGwF,EAAQ2B,QAEhC,OAAO,UAAgB0F,EAAiBC,GAItC,IAAI,GAFAiB,GAAOC,EAAOC,EADdX,EAAO,GAAI9Q,GAAS+F,IAAIgL,KAGpB9P,EAAI,EAAGA,EAAIoP,EAAgBhP,OAAQJ,GAAK,EAAG,CACjD,GAAI+P,GAAQX,EAAgBpP,GACxBgQ,EAAQZ,EAAgBpP,EAAI,GAC5BI,GAAU2P,EAAQO,GAASD,EAC3BJ,EAAWZ,EAAUrP,EAAI,EAEPoB,UAAnB6O,EAASnP,OAEMM,SAAboP,EACDX,EAAKK,KAAKH,EAAOC,GAAO,EAAOC,GAE/BJ,EAAKY,MACHH,EAAQlQ,EACRmQ,EACAR,EAAQ3P,EACR4P,EACAD,EACAC,GACA,EACAC,GAIJK,EAAQP,EACRQ,EAAQP,EACRQ,EAAWP,GACFlI,EAAQyH,YACjBc,EAAQP,EAAQS,EAAWpP,QAI/B,MAAOyO,KA0BX9Q,EAAS4Q,cAAce,SAAW,SAAS3I,GACzC,GAAIuH,IACFqB,QAAS,EACTnB,WAAW,EAGbzH,GAAUhJ,EAASe,UAAWwP,EAAgBvH,EAE9C,IAAI6I,GAAItO,KAAKyG,IAAI,EAAGzG,KAAKC,IAAI,EAAGwF,EAAQ4I,UACtCE,EAAI,EAAID,CAEV,OAAO,SAASF,GAAStB,EAAiBC,GAGxC,GAAII,GAAW1Q,EAASoQ,kBAAkBC,EAAiBC,GACzDG,UAAWzH,EAAQyH,WAGrB,IAAIC,EAASrP,OAGN,CAAA,GAAGqP,EAASrP,OAAS,EAAG,CAG3B,GAAI0Q,KAMN,OAJArB,GAAS/M,QAAQ,SAASqO,GACxBD,EAAM/K,KAAK2K,EAASK,EAAQ3B,gBAAiB2B,EAAQ1B,cAGhDtQ,EAAS+F,IAAIgL,KAAKhD,KAAKgE,GAQ9B,GAJA1B,EAAkBK,EAAS,GAAGL,gBAC9BC,EAAYI,EAAS,GAAGJ,UAGrBD,EAAgBhP,QAAU,EAC3B,MAAOrB,GAAS4Q,cAAcC,OAAOR,EAAiBC,EAMxD,KAAK,GAFH2B,GADEnB,GAAO,GAAI9Q,GAAS+F,IAAIgL,MAAOI,KAAKd,EAAgB,GAAIA,EAAgB,IAAI,EAAOC,EAAU,IAGxFrP,EAAI,EAAGiR,EAAO7B,EAAgBhP,OAAQ6Q,EAAO,GAAKD,EAAIhR,EAAGA,GAAK,EAAG,CACxE,GAAIuJ,KACD5C,GAAIyI,EAAgBpP,EAAI,GAAI0G,GAAI0I,EAAgBpP,EAAI,KACpD2G,GAAIyI,EAAgBpP,GAAI0G,GAAI0I,EAAgBpP,EAAI,KAChD2G,GAAIyI,EAAgBpP,EAAI,GAAI0G,GAAI0I,EAAgBpP,EAAI,KACpD2G,GAAIyI,EAAgBpP,EAAI,GAAI0G,GAAI0I,EAAgBpP,EAAI,IAEnDgR,GACGhR,EAEMiR,EAAO,IAAMjR,EACtBuJ,EAAE,IAAM5C,GAAIyI,EAAgB,GAAI1I,GAAI0I,EAAgB,IAC3C6B,EAAO,IAAMjR,IACtBuJ,EAAE,IAAM5C,GAAIyI,EAAgB,GAAI1I,GAAI0I,EAAgB,IACpD7F,EAAE,IAAM5C,GAAIyI,EAAgB,GAAI1I,GAAI0I,EAAgB,KALpD7F,EAAE,IAAM5C,GAAIyI,EAAgB6B,EAAO,GAAIvK,GAAI0I,EAAgB6B,EAAO,IAQhEA,EAAO,IAAMjR,EACfuJ,EAAE,GAAKA,EAAE,GACCvJ,IACVuJ,EAAE,IAAM5C,GAAIyI,EAAgBpP,GAAI0G,GAAI0I,EAAgBpP,EAAI,KAI5D6P,EAAKY,MACFG,IAAMrH,EAAE,GAAG5C,EAAI,EAAI4C,EAAE,GAAG5C,EAAI4C,EAAE,GAAG5C,GAAK,EAAMkK,EAAItH,EAAE,GAAG5C,EACrDiK,IAAMrH,EAAE,GAAG7C,EAAI,EAAI6C,EAAE,GAAG7C,EAAI6C,EAAE,GAAG7C,GAAK,EAAMmK,EAAItH,EAAE,GAAG7C,EACrDkK,GAAKrH,EAAE,GAAG5C,EAAI,EAAI4C,EAAE,GAAG5C,EAAI4C,EAAE,GAAG5C,GAAK,EAAMkK,EAAItH,EAAE,GAAG5C,EACpDiK,GAAKrH,EAAE,GAAG7C,EAAI,EAAI6C,EAAE,GAAG7C,EAAI6C,EAAE,GAAG7C,GAAK,EAAMmK,EAAItH,EAAE,GAAG7C,EACrD6C,EAAE,GAAG5C,EACL4C,EAAE,GAAG7C,GACL,EACA2I,GAAWrP,EAAI,GAAK,IAIxB,MAAO6P,GA7DP,MAAO9Q,GAAS4Q,cAAcC,aAyFpC7Q,EAAS4Q,cAAcuB,cAAgB,SAASnJ,GAC9C,GAAIuH,IACFE,WAAW,EAKb,OAFAzH,GAAUhJ,EAASe,UAAWwP,EAAgBvH,GAEvC,QAASmJ,GAAc9B,EAAiBC,GAG7C,GAAII,GAAW1Q,EAASoQ,kBAAkBC,EAAiBC,GACzDG,UAAWzH,EAAQyH,UACnBD,aAAa,GAGf,IAAIE,EAASrP,OAGN,CAAA,GAAGqP,EAASrP,OAAS,EAAG,CAG3B,GAAI0Q,KAMN,OAJArB,GAAS/M,QAAQ,SAASqO,GACxBD,EAAM/K,KAAKmL,EAAcH,EAAQ3B,gBAAiB2B,EAAQ1B,cAGrDtQ,EAAS+F,IAAIgL,KAAKhD,KAAKgE,GAQ9B,GAJA1B,EAAkBK,EAAS,GAAGL,gBAC9BC,EAAYI,EAAS,GAAGJ,UAGrBD,EAAgBhP,QAAU,EAC3B,MAAOrB,GAAS4Q,cAAcC,OAAOR,EAAiBC,EAGxD,IAEErP,GAIA6P,EANEsB,KACFC,KAEA1R,EAAI0P,EAAgBhP,OAAS,EAC7BiR,KACAC,KAASC,KAAUC,IAKrB,KAAIxR,EAAI,EAAGA,EAAIN,EAAGM,IAChBmR,EAAGnR,GAAKoP,EAAoB,EAAJpP,GACxBoR,EAAGpR,GAAKoP,EAAoB,EAAJpP,EAAQ,EAKlC,KAAIA,EAAI,EAAGA,EAAIN,EAAI,EAAGM,IACpBuR,EAAIvR,GAAKoR,EAAGpR,EAAI,GAAKoR,EAAGpR,GACxBwR,EAAIxR,GAAKmR,EAAGnR,EAAI,GAAKmR,EAAGnR,GACxBsR,EAAGtR,GAAKuR,EAAIvR,GAAKwR,EAAIxR,EASvB,KAHAqR,EAAG,GAAKC,EAAG,GACXD,EAAG3R,EAAI,GAAK4R,EAAG5R,EAAI,GAEfM,EAAI,EAAGA,EAAIN,EAAI,EAAGM,IACP,IAAVsR,EAAGtR,IAA0B,IAAdsR,EAAGtR,EAAI,IAAasR,EAAGtR,EAAI,GAAK,GAAQsR,EAAGtR,GAAK,EAChEqR,EAAGrR,GAAK,GAERqR,EAAGrR,GAAK,GAAKwR,EAAIxR,EAAI,GAAKwR,EAAIxR,MAC3B,EAAIwR,EAAIxR,GAAKwR,EAAIxR,EAAI,IAAMsR,EAAGtR,EAAI,IAClCwR,EAAIxR,GAAK,EAAIwR,EAAIxR,EAAI,IAAMsR,EAAGtR,IAE7BiJ,SAASoI,EAAGrR,MACdqR,EAAGrR,GAAK,GASd,KAFA6P,GAAO,GAAI9Q,GAAS+F,IAAIgL,MAAOI,KAAKiB,EAAG,GAAIC,EAAG,IAAI,EAAO/B,EAAU,IAE/DrP,EAAI,EAAGA,EAAIN,EAAI,EAAGM,IACpB6P,EAAKY,MAEHU,EAAGnR,GAAKwR,EAAIxR,GAAK,EACjBoR,EAAGpR,GAAKqR,EAAGrR,GAAKwR,EAAIxR,GAAK,EAEzBmR,EAAGnR,EAAI,GAAKwR,EAAIxR,GAAK,EACrBoR,EAAGpR,EAAI,GAAKqR,EAAGrR,EAAI,GAAKwR,EAAIxR,GAAK,EAEjCmR,EAAGnR,EAAI,GACPoR,EAAGpR,EAAI,IAEP,EACAqP,EAAUrP,EAAI,GAIlB,OAAO6P,GAtFP,MAAO9Q,GAAS4Q,cAAcC,aA+GpC7Q,EAAS4Q,cAAcnF,KAAO,SAASzC,GACrC,GAAIuH,IACFmC,UAAU,EACVjC,WAAW,EAKb,OAFAzH,GAAUhJ,EAASe,UAAWwP,EAAgBvH,GAEvC,SAAcqH,EAAiBC,GAKpC,IAAK,GAFDiB,GAAOC,EAAOC,EAFdX,EAAO,GAAI9Q,GAAS+F,IAAIgL,KAInB9P,EAAI,EAAGA,EAAIoP,EAAgBhP,OAAQJ,GAAK,EAAG,CAClD,GAAI+P,GAAQX,EAAgBpP,GACxBgQ,EAAQZ,EAAgBpP,EAAI,GAC5BiQ,EAAWZ,EAAUrP,EAAI,EAGPoB,UAAnB6O,EAASnP,OACMM,SAAboP,EACDX,EAAKK,KAAKH,EAAOC,GAAO,EAAOC,IAE5BlI,EAAQ0J,SAET5B,EAAKM,KAAKJ,EAAOQ,GAAO,EAAOC,GAG/BX,EAAKM,KAAKG,EAAON,GAAO,EAAOC,GAGjCJ,EAAKM,KAAKJ,EAAOC,GAAO,EAAOC,IAGjCK,EAAQP,EACRQ,EAAQP,EACRQ,EAAWP,GACFlI,EAAQyH,YACjBc,EAAQC,EAAQC,EAAWpP,QAI/B,MAAOyO,MAIX5Q,OAAQC,SAAUH,GAOnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEAA,GAAS2S,aAAe,WAUtB,QAASC,GAAgBC,EAAOC,GAC9BC,EAASF,GAASE,EAASF,OAC3BE,EAASF,GAAO7L,KAAK8L,GAUvB,QAASE,GAAmBH,EAAOC,GAE9BC,EAASF,KAEPC,GACDC,EAASF,GAAOI,OAAOF,EAASF,GAAOK,QAAQJ,GAAU,GAC3B,IAA3BC,EAASF,GAAOxR,cACV0R,GAASF,UAIXE,GAASF,IAYtB,QAAS7E,GAAK6E,EAAOnO,GAEhBqO,EAASF,IACVE,EAASF,GAAOlP,QAAQ,SAASmP,GAC/BA,EAAQpO,KAKTqO,EAAS,MACVA,EAAS,KAAKpP,QAAQ,SAASwP,GAC7BA,EAAYN,EAAOnO,KAvDzB,GAAIqO,KA4DJ,QACEH,gBAAiBA,EACjBI,mBAAoBA,EACpBhF,KAAMA,KAIV9N,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAEA,SAASoT,GAAYC,GACnB,GAAIjQ,KACJ,IAAIiQ,EAAKhS,OACP,IAAK,GAAIJ,GAAI,EAAGA,EAAIoS,EAAKhS,OAAQJ,IAC/BmC,EAAI4D,KAAKqM,EAAKpS,GAGlB,OAAOmC,GA4CT,QAASrC,GAAOuS,EAAYC,GAC1B,GAAIC,GAAaD,GAAsBxT,KAAKyF,WAAaxF,EAASyT,MAC9DC,EAAQ7O,OAAO8O,OAAOH,EAE1BxT,GAASyT,MAAMG,iBAAiBF,EAAOJ,EAEvC,IAAIO,GAAS,WACX,GACEC,GADEC,EAAKL,EAAMM,aAAe,YAU9B,OALAF,GAAW/T,OAASC,EAAW6E,OAAO8O,OAAOD,GAAS3T,KACtDgU,EAAGrR,MAAMoR,EAAUvS,MAAMiE,UAAUC,MAAMC,KAAKtE,UAAW,IAIlD0S,EAOT,OAJAD,GAAOrO,UAAYkO,EACnBG,EAAAA,SAAeL,EACfK,EAAO9S,OAAShB,KAAKgB,OAEd8S,EAIT,QAASD,KACP,GAAI/P,GAAOuP,EAAYhS,WACnBJ,EAAS6C,EAAK,EAYlB,OAVAA,GAAKoP,OAAO,EAAGpP,EAAKxC,OAAS,GAAGsC,QAAQ,SAAUzC,GAChD2D,OAAOoP,oBAAoB/S,GAAQyC,QAAQ,SAAUuQ,SAE5ClT,GAAOkT,GAEdrP,OAAOsP,eAAenT,EAAQkT,EAC5BrP,OAAOuP,yBAAyBlT,EAAQgT,QAIvClT,EAGThB,EAASyT,OACP1S,OAAQA,EACR6S,iBAAkBA,IAGpB1T,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAgBA,SAASqU,GAAO3P,EAAMsE,EAASsL,GA6B7B,MA5BG5P,KACD3E,KAAK2E,KAAOA,MACZ3E,KAAK2E,KAAKqC,OAAShH,KAAK2E,KAAKqC,WAC7BhH,KAAK2E,KAAKkC,OAAS7G,KAAK2E,KAAKkC,WAE7B7G,KAAKyN,aAAaQ,KAAK,QACrBC,KAAM,SACNvJ,KAAM3E,KAAK2E,QAIZsE,IACDjJ,KAAKiJ,QAAUhJ,EAASe,UAAWuT,EAAWvU,KAAKiJ,QAAUjJ,KAAKwQ,eAAgBvH,GAI9EjJ,KAAKwU,sBACPxU,KAAKsP,gBAAgBU,4BACrBhQ,KAAKsP,gBAAkBrP,EAASqP,gBAAgBtP,KAAKiJ,QAASjJ,KAAKuP,kBAAmBvP,KAAKyN,gBAK3FzN,KAAKwU,qBACPxU,KAAKyU,YAAYzU,KAAKsP,gBAAgBc,qBAIjCpQ,KAQT,QAAS0U,KAUP,MAPI1U,MAAKwU,oBAIPrU,EAAOwU,aAAa3U,KAAKwU,sBAHzBrU,EAAOyU,oBAAoB,SAAU5U,KAAK6U,gBAC1C7U,KAAKsP,gBAAgBU,6BAKhBhQ,KAUT,QAAS8U,GAAGhC,EAAOC,GAEjB,MADA/S,MAAKyN,aAAaoF,gBAAgBC,EAAOC,GAClC/S,KAUT,QAAS+U,GAAIjC,EAAOC,GAElB,MADA/S,MAAKyN,aAAawF,mBAAmBH,EAAOC,GACrC/S,KAGT,QAASgV,KAEP7U,EAAO8U,iBAAiB,SAAUjV,KAAK6U,gBAIvC7U,KAAKsP,gBAAkBrP,EAASqP,gBAAgBtP,KAAKiJ,QAASjJ,KAAKuP,kBAAmBvP,KAAKyN,cAE3FzN,KAAKyN,aAAaoF,gBAAgB,iBAAkB,WAClD7S,KAAKsU,UACLY,KAAKlV,OAIJA,KAAKiJ,QAAQkM,SACdnV,KAAKiJ,QAAQkM,QAAQvR,QAAQ,SAASwR,GACjCA,YAAkB5T,OACnB4T,EAAO,GAAGpV,KAAMoV,EAAO,IAEvBA,EAAOpV,OAETkV,KAAKlV,OAITA,KAAKyN,aAAaQ,KAAK,QACrBC,KAAM,UACNvJ,KAAM3E,KAAK2E,OAIb3E,KAAKyU,YAAYzU,KAAKsP,gBAAgBc,qBAItCpQ,KAAKwU,oBAAsBlS,OAa7B,QAAS+S,GAAK7S,EAAOmC,EAAM6L,EAAgBvH,EAASsG,GAClDvP,KAAKqF,UAAYpF,EAASsC,cAAcC,GACxCxC,KAAK2E,KAAOA,MACZ3E,KAAK2E,KAAKqC,OAAShH,KAAK2E,KAAKqC,WAC7BhH,KAAK2E,KAAKkC,OAAS7G,KAAK2E,KAAKkC,WAC7B7G,KAAKwQ,eAAiBA,EACtBxQ,KAAKiJ,QAAUA,EACfjJ,KAAKuP,kBAAoBA,EACzBvP,KAAKyN,aAAexN,EAAS2S,eAC7B5S,KAAKsV,sBAAwBrV,EAAS+F,IAAIuP,YAAY,iBACtDvV,KAAKwV,mBAAqBvV,EAAS+F,IAAIuP,YAAY,4BACnDvV,KAAK6U,eAAiB,WACpB7U,KAAKsU,UACLY,KAAKlV,MAEJA,KAAKqF,YAEHrF,KAAKqF,UAAUoQ,cAChBzV,KAAKqF,UAAUoQ,aAAaf,SAG9B1U,KAAKqF,UAAUoQ,aAAezV,MAKhCA,KAAKwU,oBAAsBkB,WAAWV,EAAWE,KAAKlV,MAAO,GAI/DC,EAASoV,KAAOpV,EAASyT,MAAM1S,QAC7BiT,YAAaoB,EACb/F,gBAAiBhN,OACjB+C,UAAW/C,OACXhC,IAAKgC,OACLmL,aAAcnL,OACdmS,YAAa,WACX,KAAM,IAAI1I,OAAM,2CAElBuI,OAAQA,EACRI,OAAQA,EACRI,GAAIA,EACJC,IAAKA,EACL7U,QAASD,EAASC,QAClBoV,uBAAuB,KAGzBnV,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YAaA,SAAS+F,GAAIoJ,EAAMuG,EAAYnQ,EAAWoQ,EAAQC,GAE7CzG,YAAgB0G,SACjB9V,KAAKmG,MAAQiJ,GAEbpP,KAAKmG,MAAQ/F,EAAS2V,gBAAgB9V,EAASI,WAAWC,IAAK8O,GAGnD,QAATA,GACDpP,KAAKiG,MACH+P,WAAY/V,EAASI,WAAWK,MAKnCiV,GACD3V,KAAKiG,KAAK0P,GAGTnQ,GACDxF,KAAKkG,SAASV,GAGboQ,IACGC,GAAeD,EAAOzP,MAAM8P,WAC9BL,EAAOzP,MAAM+P,aAAalW,KAAKmG,MAAOyP,EAAOzP,MAAM8P,YAEnDL,EAAOzP,MAAME,YAAYrG,KAAKmG,QAapC,QAASF,GAAK0P,EAAYQ,GACxB,MAAyB,gBAAfR,GACLQ,EACMnW,KAAKmG,MAAML,eAAeqQ,EAAIR,GAE9B3V,KAAKmG,MAAMiQ,aAAaT,IAInC7Q,OAAOC,KAAK4Q,GAAY/R,QAAQ,SAASqB,GAEvC,GAAuB3C,SAApBqT,EAAW1Q,GAId,GAAIA,EAAIkO,QAAQ,UAAa,CAC3B,GAAIkD,GAAsBpR,EAAIqR,MAAM,IACpCtW,MAAKmG,MAAMoQ,eAAetW,EAASI,WAAWgW,EAAoB,IAAKpR,EAAK0Q,EAAW1Q,QAEvFjF,MAAKmG,MAAM4I,aAAa9J,EAAK0Q,EAAW1Q,KAE1CiQ,KAAKlV,OAEAA,MAaT,QAAS+N,GAAKqB,EAAMuG,EAAYnQ,EAAWqQ,GACzC,MAAO,IAAI5V,GAAS+F,IAAIoJ,EAAMuG,EAAYnQ,EAAWxF,KAAM6V,GAS7D,QAASD,KACP,MAAO5V,MAAKmG,MAAMqQ,qBAAsBC,YAAa,GAAIxW,GAAS+F,IAAIhG,KAAKmG,MAAMqQ,YAAc,KASjG,QAAS9W,KAEP,IADA,GAAIgX,GAAO1W,KAAKmG,MACQ,QAAlBuQ,EAAKC,UACTD,EAAOA,EAAKF,UAEd,OAAO,IAAIvW,GAAS+F,IAAI0Q,GAU1B,QAASnU,GAAcqU,GACrB,GAAIC,GAAY7W,KAAKmG,MAAM5D,cAAcqU,EACzC,OAAOC,GAAY,GAAI5W,GAAS+F,IAAI6Q,GAAa,KAUnD,QAASjR,GAAiBgR,GACxB,GAAIE,GAAa9W,KAAKmG,MAAMP,iBAAiBgR,EAC7C,OAAOE,GAAWxV,OAAS,GAAIrB,GAAS+F,IAAI+Q,KAAKD,GAAc,KASjE,QAASE,KACP,MAAOhX,MAAKmG,MAad,QAAS8I,GAAcJ,EAAS8G,EAAYnQ,EAAWqQ,GAGrD,GAAsB,gBAAZhH,GAAsB,CAC9B,GAAIxJ,GAAYjF,EAAS0O,cAAc,MACvCzJ,GAAU4R,UAAYpI,EACtBA,EAAUxJ,EAAU4Q,WAItBpH,EAAQE,aAAa,QAAS9O,EAASI,WAAWE,MAIlD,IAAI2W,GAAQlX,KAAK+N,KAAK,gBAAiB4H,EAAYnQ,EAAWqQ,EAK9D,OAFAqB,GAAM/Q,MAAME,YAAYwI,GAEjBqI,EAUT,QAAShI,GAAK4C,GAEZ,MADA9R,MAAKmG,MAAME,YAAYjG,EAAS+W,eAAerF,IACxC9R,KAST,QAASoX,KACP,KAAOpX,KAAKmG,MAAM8P,YAChBjW,KAAKmG,MAAMJ,YAAY/F,KAAKmG,MAAM8P,WAGpC,OAAOjW,MAST,QAASqX,KAEP,MADArX,MAAKmG,MAAMqQ,WAAWzQ,YAAY/F,KAAKmG,OAChCnG,KAAK4V,SAUd,QAAS/T,GAAQyV,GAEf,MADAtX,MAAKmG,MAAMqQ,WAAWe,aAAaD,EAAWnR,MAAOnG,KAAKmG,OACnDmR,EAWT,QAASE,GAAOrJ,EAAS0H,GAOvB,MANGA,IAAe7V,KAAKmG,MAAM8P,WAC3BjW,KAAKmG,MAAM+P,aAAa/H,EAAQhI,MAAOnG,KAAKmG,MAAM8P,YAElDjW,KAAKmG,MAAME,YAAY8H,EAAQhI,OAG1BnG,KAST,QAASwN,KACP,MAAOxN,MAAKmG,MAAMiQ,aAAa,SAAWpW,KAAKmG,MAAMiQ,aAAa,SAASqB,OAAOnB,MAAM,UAU1F,QAASpQ,GAASwR,GAShB,MARA1X,MAAKmG,MAAM4I,aAAa,QACtB/O,KAAKwN,QAAQxN,KAAKmG,OACfwR,OAAOD,EAAMD,OAAOnB,MAAM,QAC1BzQ,OAAO,SAASkI,EAAMH,EAAKgK,GAC1B,MAAOA,GAAKzE,QAAQpF,KAAUH,IAC7BI,KAAK,MAGLhO,KAUT,QAAS6X,GAAYH,GACnB,GAAII,GAAiBJ,EAAMD,OAAOnB,MAAM,MAMxC,OAJAtW,MAAKmG,MAAM4I,aAAa,QAAS/O,KAAKwN,QAAQxN,KAAKmG,OAAON,OAAO,SAASuJ,GACxE,MAAO0I,GAAe3E,QAAQ/D,UAC7BpB,KAAK,MAEDhO,KAST,QAAS+X,KAGP,MAFA/X,MAAKmG,MAAM4I,aAAa,QAAS,IAE1B/O,KAST,QAASuF,KACP,MAAOvF,MAAKmG,MAAM6R,wBAAwBzS,OAS5C,QAASD,KACP,MAAOtF,MAAKmG,MAAM6R,wBAAwB1S,MA4C5C,QAAS2S,GAAQC,EAAYC,EAAQ1K,GA4GnC,MA3GcnL,UAAX6V,IACDA,GAAS,GAGXrT,OAAOC,KAAKmT,GAAYtU,QAAQ,SAAoCwU,GAElE,QAASC,GAAcC,EAAqBH,GAC1C,GACEF,GACAM,EACAC,EAHEC,IAODH,GAAoBE,SAErBA,EAASF,EAAoBE,iBAAkBhX,OAC7C8W,EAAoBE,OACpBvY,EAAS+F,IAAI0S,OAAOJ,EAAoBE,cACnCF,GAAoBE,QAI7BF,EAAoBK,MAAQ1Y,EAAS8B,WAAWuW,EAAoBK,MAAO,MAC3EL,EAAoBM,IAAM3Y,EAAS8B,WAAWuW,EAAoBM,IAAK,MAEpEJ,IACDF,EAAoBO,SAAW,SAC/BP,EAAoBQ,WAAaN,EAAOxK,KAAK,KAC7CsK,EAAoBS,SAAW,OAI9BZ,IACDG,EAAoBU,KAAO,SAE3BP,EAAoBL,GAAaE,EAAoBW,KACrDjZ,KAAKiG,KAAKwS,GAIVF,EAAUtY,EAASiC,SAASoW,EAAoBK,OAAS,GAAG3W,MAC5DsW,EAAoBK,MAAQ,cAG9BV,EAAUjY,KAAK+N,KAAK,UAAW9N,EAASe,QACtCkY,cAAed,GACdE,IAEAH,GAEDzC,WAAW,WAIT,IACEuC,EAAQ9R,MAAMgT,eACd,MAAMC,GAENX,EAAoBL,GAAaE,EAAoBe,GACrDrZ,KAAKiG,KAAKwS,GAEVR,EAAQZ,WAEVnC,KAAKlV,MAAOuY,GAGb9K,GACDwK,EAAQ9R,MAAM8O,iBAAiB,aAAc,WAC3CxH,EAAaQ,KAAK,kBAChBE,QAASnO,KACTiY,QAASA,EAAQ9R,MACjBmT,OAAQhB,KAEVpD,KAAKlV,OAGTiY,EAAQ9R,MAAM8O,iBAAiB,WAAY,WACtCxH,GACDA,EAAaQ,KAAK,gBAChBE,QAASnO,KACTiY,QAASA,EAAQ9R,MACjBmT,OAAQhB,IAITH,IAEDM,EAAoBL,GAAaE,EAAoBe,GACrDrZ,KAAKiG,KAAKwS,GAEVR,EAAQZ,WAEVnC,KAAKlV,OAINkY,EAAWE,YAAsB5W,OAClC0W,EAAWE,GAAWxU,QAAQ,SAAS0U,GACrCD,EAAcnD,KAAKlV,MAAMsY,GAAqB,IAC9CpD,KAAKlV,OAEPqY,EAAcnD,KAAKlV,MAAMkY,EAAWE,GAAYD,IAGlDjD,KAAKlV,OAEAA,KAgFT,QAASuZ,GAAQC,GACf,GAAIlG,GAAOtT,IAEXA,MAAKyZ,cACL,KAAI,GAAIvY,GAAI,EAAGA,EAAIsY,EAASlY,OAAQJ,IAClClB,KAAKyZ,YAAYxS,KAAK,GAAIhH,GAAS+F,IAAIwT,EAAStY,IAIlD4D,QAAOC,KAAK9E,EAAS+F,IAAIP,WAAWI,OAAO,SAAS6T,GAClD,OAAQ,cACJ,SACA,gBACA,mBACA,UACA,SACA,UACA,SACA,SAASvG,QAAQuG,UACpB9V,QAAQ,SAAS8V,GAClBpG,EAAKoG,GAAqB,WACxB,GAAI5V,GAAOtC,MAAMiE,UAAUC,MAAMC,KAAKtE,UAAW,EAIjD,OAHAiS,GAAKmG,YAAY7V,QAAQ,SAASuK,GAChClO,EAAS+F,IAAIP,UAAUiU,GAAmB/W,MAAMwL,EAASrK,KAEpDwP,KAtGbrT,EAAS+F,IAAM/F,EAASyT,MAAM1S,QAC5BiT,YAAajO,EACbC,KAAMA,EACN8H,KAAMA,EACN6H,OAAQA,EACRlW,KAAMA,EACN6C,cAAeA,EACfqD,iBAAkBA,EAClBoR,QAASA,EACT/H,cAAeA,EACfC,KAAMA,EACNkI,MAAOA,EACPC,OAAQA,EACRxV,QAASA,EACT2V,OAAQA,EACRhK,QAASA,EACTtH,SAAUA,EACV2R,YAAaA,EACbE,iBAAkBA,EAClBxS,OAAQA,EACRD,MAAOA,EACP2S,QAASA,IAUXhY,EAAS+F,IAAIuP,YAAc,SAASoE,GAClC,MAAOvZ,GAASwZ,eAAeC,WAAW,sCAAwCF,EAAS,OAQ7F,IAAIG,IACFC,YAAa,IAAM,EAAG,KAAO,MAC7BC,aAAc,IAAM,KAAO,KAAO,GAClCC,eAAgB,KAAO,IAAM,IAAM,KACnCC,YAAa,IAAM,KAAO,IAAM,KAChCC,aAAc,IAAM,IAAM,IAAM,KAChCC,eAAgB,KAAO,IAAM,KAAO,MACpCC,aAAc,IAAM,KAAO,KAAO,KAClCC,cAAe,KAAO,IAAM,KAAO,GACnCC,gBAAiB,KAAO,KAAO,KAAO,GACtCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,KAAO,IAAM,IAAM,GAClCC,gBAAiB,IAAM,EAAG,KAAO,GACjCC,aAAc,KAAO,IAAM,KAAO,KAClCC,cAAe,IAAM,EAAG,IAAM,GAC9BC,gBAAiB,IAAM,EAAG,IAAM,GAChCC,YAAa,IAAM,IAAM,KAAO,MAChCC,aAAc,IAAM,EAAG,IAAM,GAC7BC,eAAgB,EAAG,EAAG,EAAG,GACzBC,YAAa,GAAK,IAAM,IAAM,MAC9BC,aAAc,KAAO,IAAM,KAAO,GAClCC,eAAgB,KAAO,KAAO,IAAM,KACpCC,YAAa,QAAY,KAAO,MAChCC,aAAc,KAAO,KAAO,IAAM,OAClCC,eAAgB,SAAa,KAAO,MAGtCrb,GAAS+F,IAAI0S,OAASoB,EAwCtB7Z,EAAS+F,IAAI+Q,KAAO9W,EAASyT,MAAM1S,QACjCiT,YAAasF,KAEfpZ,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA0BA,SAASkO,GAAQoN,EAASjC,EAAQkC,EAAc5N,EAAK6N,EAAU9W,GAC7D,GAAI+W,GAAczb,EAASe,QACzBua,QAASE,EAAWF,EAAQI,cAAgBJ,EAAQ1R,eACnDyP,EAAQ3U,GAASA,KAAMA,MAE1B6W,GAAatI,OAAOtF,EAAK,EAAG8N,GAG9B,QAASE,GAAaJ,EAAclY,GAClCkY,EAAa5X,QAAQ,SAAS8X,EAAaG,GACzCC,EAAoBJ,EAAYH,QAAQI,eAAe/X,QAAQ,SAASmY,EAAWC,GACjF1Y,EAAGoY,EAAaK,EAAWF,EAAkBG,EAAYR,OAa/D,QAASS,GAAQC,EAAOjT,GACtBjJ,KAAKwb,gBACLxb,KAAK4N,IAAM,EACX5N,KAAKkc,MAAQA,EACblc,KAAKiJ,QAAUhJ,EAASe,UAAWwP,EAAgBvH,GAUrD,QAASmE,GAASQ,GAChB,MAAWtL,UAARsL,GACD5N,KAAK4N,IAAMpK,KAAKC,IAAI,EAAGD,KAAKyG,IAAIjK,KAAKwb,aAAala,OAAQsM,IACnD5N,MAEAA,KAAK4N,IAWhB,QAASyJ,GAAO8E,GAEd,MADAnc,MAAKwb,aAAatI,OAAOlT,KAAK4N,IAAKuO,GAC5Bnc,KAaT,QAASoR,GAAKvJ,EAAGD,EAAG6T,EAAU9W,GAK5B,MAJAwJ,GAAQ,KACNtG,GAAIA,EACJD,GAAIA,GACH5H,KAAKwb,aAAcxb,KAAK4N,MAAO6N,EAAU9W,GACrC3E,KAaT,QAASqR,GAAKxJ,EAAGD,EAAG6T,EAAU9W,GAK5B,MAJAwJ,GAAQ,KACNtG,GAAIA,EACJD,GAAIA,GACH5H,KAAKwb,aAAcxb,KAAK4N,MAAO6N,EAAU9W,GACrC3E,KAiBT,QAAS2R,GAAM9G,EAAIqC,EAAIpC,EAAIqC,EAAItF,EAAGD,EAAG6T,EAAU9W,GAS7C,MARAwJ,GAAQ,KACNtD,IAAKA,EACLqC,IAAKA,EACLpC,IAAKA,EACLqC,IAAKA,EACLtF,GAAIA,EACJD,GAAIA,GACH5H,KAAKwb,aAAcxb,KAAK4N,MAAO6N,EAAU9W,GACrC3E,KAkBT,QAASoc,GAAIC,EAAIC,EAAIC,EAAKC,EAAKC,EAAI5U,EAAGD,EAAG6T,EAAU9W,GAUjD,MATAwJ,GAAQ,KACNkO,IAAKA,EACLC,IAAKA,EACLC,KAAMA,EACNC,KAAMA,EACNC,IAAKA,EACL5U,GAAIA,EACJD,GAAIA,GACH5H,KAAKwb,aAAcxb,KAAK4N,MAAO6N,EAAU9W,GACrC3E,KAUT,QAASmF,GAAM4L,GAEb,GAAI2L,GAAS3L,EAAKlP,QAAQ,qBAAsB,SAC7CA,QAAQ,qBAAsB,SAC9ByU,MAAM,UACNtR,OAAO,SAASzB,EAAQ4K,GAMvB,MALGA,GAAQ/L,MAAM,aACfmB,EAAO0D,SAGT1D,EAAOA,EAAOjC,OAAS,GAAG2F,KAAKkH,GACxB5K,MAIuC,OAA/CmZ,EAAOA,EAAOpb,OAAS,GAAG,GAAGuI,eAC9B6S,EAAOC,KAKT,IAAIC,GAAWF,EAAOhZ,IAAI,SAASmZ,GAC/B,GAAItB,GAAUsB,EAAMC,QAClBC,EAAcjB,EAAoBP,EAAQI,cAE5C,OAAO1b,GAASe,QACdua,QAASA,GACRwB,EAAY/X,OAAO,SAASzB,EAAQwY,EAAWlY,GAEhD,MADAN,GAAOwY,IAAcc,EAAMhZ,GACpBN,UAKTyZ,GAAchd,KAAK4N,IAAK,EAM5B,OALApM,OAAMiE,UAAUwB,KAAKtE,MAAMqa,EAAYJ,GACvCpb,MAAMiE,UAAUyN,OAAOvQ,MAAM3C,KAAKwb,aAAcwB,GAEhDhd,KAAK4N,KAAOgP,EAAStb,OAEdtB,KAST,QAAS6E,KACP,GAAIoY,GAAqBzZ,KAAKU,IAAI,GAAIlE,KAAKiJ,QAAQiU,SAEnD,OAAOld,MAAKwb,aAAaxW,OAAO,SAAS+L,EAAM2K,GAC3C,GAAIpC,GAASwC,EAAoBJ,EAAYH,QAAQI,eAAejY,IAAI,SAASqY,GAC/E,MAAO/b,MAAKiJ,QAAQiU,SACjB1Z,KAAKW,MAAMuX,EAAYK,GAAakB,GAAsBA,EAC3DvB,EAAYK,IACd7G,KAAKlV,MAEP,OAAO+Q,GAAO2K,EAAYH,QAAUjC,EAAOtL,KAAK,MAChDkH,KAAKlV,MAAO,KAAOA,KAAKkc,MAAQ,IAAM,IAW5C,QAASiB,GAAMtV,EAAGD,GAIhB,MAHAgU,GAAa5b,KAAKwb,aAAc,SAASE,EAAaK,GACpDL,EAAYK,IAA+B,MAAjBA,EAAU,GAAalU,EAAID,IAEhD5H,KAWT,QAASod,GAAUvV,EAAGD,GAIpB,MAHAgU,GAAa5b,KAAKwb,aAAc,SAASE,EAAaK,GACpDL,EAAYK,IAA+B,MAAjBA,EAAU,GAAalU,EAAID,IAEhD5H,KAeT,QAASqd,GAAUC,GAOjB,MANA1B,GAAa5b,KAAKwb,aAAc,SAASE,EAAaK,EAAWF,EAAkBG,EAAYR,GAC7F,GAAI+B,GAAcD,EAAa5B,EAAaK,EAAWF,EAAkBG,EAAYR,IAClF+B,GAA+B,IAAhBA,KAChB7B,EAAYK,GAAawB,KAGtBvd,KAUT,QAASwd,GAAMtB,GACb,GAAInK,GAAI,GAAI9R,GAAS+F,IAAIgL,KAAKkL,GAASlc,KAAKkc,MAM5C,OALAnK,GAAEnE,IAAM5N,KAAK4N,IACbmE,EAAEyJ,aAAexb,KAAKwb,aAAa9V,QAAQhC,IAAI,SAAuBgY,GACpE,MAAOzb,GAASe,UAAW0a,KAE7B3J,EAAE9I,QAAUhJ,EAASe,UAAWhB,KAAKiJ,SAC9B8I,EAUT,QAAS0L,GAAelC,GACtB,GAAIjF,IACF,GAAIrW,GAAS+F,IAAIgL,KAWnB,OARAhR,MAAKwb,aAAa5X,QAAQ,SAAS8X,GAC9BA,EAAYH,UAAYA,EAAQ1R,eAAiE,IAAhDyM,EAAMA,EAAMhV,OAAS,GAAGka,aAAala,QACvFgV,EAAMrP,KAAK,GAAIhH,GAAS+F,IAAIgL,MAG9BsF,EAAMA,EAAMhV,OAAS,GAAGka,aAAavU,KAAKyU,KAGrCpF,EAaT,QAAStI,GAAKgE,EAAOkK,EAAOjT,GAE1B,IAAI,GADAyU,GAAa,GAAIzd,GAAS+F,IAAIgL,KAAKkL,EAAOjT,GACtC/H,EAAI,EAAGA,EAAI8Q,EAAM1Q,OAAQJ,IAE/B,IAAI,GADA6P,GAAOiB,EAAM9Q,GACTyc,EAAI,EAAGA,EAAI5M,EAAKyK,aAAala,OAAQqc,IAC3CD,EAAWlC,aAAavU,KAAK8J,EAAKyK,aAAamC,GAGnD,OAAOD,GA3VT,GAAI5B,IACF8B,GAAI,IAAK,KACTC,GAAI,IAAK,KACT9L,GAAI,KAAM,KAAM,KAAM,KAAM,IAAK,KACjC+L,GAAI,KAAM,KAAM,MAAO,MAAO,KAAM,IAAK,MASvCtN,GAEF0M,SAAU,EA+UZjd,GAAS+F,IAAIgL,KAAO/Q,EAASyT,MAAM1S,QACjCiT,YAAagI,EACb7O,SAAUA,EACViK,OAAQA,EACRjG,KAAMA,EACNC,KAAMA,EACNM,MAAOA,EACPyK,IAAKA,EACLe,MAAOA,EACPC,UAAWA,EACXC,UAAWA,EACXlY,MAAOA,EACPN,UAAWA,EACX2Y,MAAOA,EACPC,eAAgBA,IAGlBxd,EAAS+F,IAAIgL,KAAK8K,oBAAsBA,EACxC7b,EAAS+F,IAAIgL,KAAKhD,KAAOA,GACzB7N,OAAQC,SAAUH,GAEnB,SAAUE,EAAQC,EAAUH,GAC3B,YAqBA,SAAS8d,GAAKpQ,EAAOV,EAAW+Q,EAAO/U,GACrCjJ,KAAK2N,MAAQA,EACb3N,KAAK6N,aAAeF,IAAUsQ,EAAUpW,EAAIoW,EAAUrW,EAAIqW,EAAUpW,EACpE7H,KAAKiN,UAAYA,EACjBjN,KAAK6I,WAAaoE,EAAUU,EAAMuQ,SAAWjR,EAAUU,EAAMwQ,WAC7Dne,KAAKoe,WAAanR,EAAUU,EAAM0Q,YAClCre,KAAKge,MAAQA,EACbhe,KAAKiJ,QAAUA,EAGjB,QAASqV,GAAoBjQ,EAAWkQ,EAAY7P,EAAkB8P,EAAc/Q,GAClF,GAAIgR,GAAcD,EAAa,OAASxe,KAAK2N,MAAMC,IAAI/D,eACnD6U,EAAkB1e,KAAKge,MAAMta,IAAI1D,KAAK2e,aAAazJ,KAAKlV,OACxD4e,EAAc5e,KAAKge,MAAMta,IAAI+a,EAAYI,sBAE7CH,GAAgB9a,QAAQ,SAASkb,EAAgBjb,GAC/C,GAOIkb,GAPAtQ,GACF5G,EAAG,EACHD,EAAG,EAQHmX,GAFCL,EAAgB7a,EAAQ,GAEX6a,EAAgB7a,EAAQ,GAAKib,EAK7Btb,KAAKC,IAAIzD,KAAK6I,WAAaiW,EAAgB,IAIxD7e,EAASmK,gBAAgBwU,EAAY/a,KAAkC,KAAvB+a,EAAY/a,KAMzC,MAAnB7D,KAAK2N,MAAMC,KACZkR,EAAiB9e,KAAKiN,UAAUpC,GAAKiU,EACrCrQ,EAAY5G,EAAI2W,EAAarV,MAAMsF,YAAY5G,EAIZ,UAAhC2W,EAAarV,MAAMiE,SACpBqB,EAAY7G,EAAI5H,KAAKiN,UAAUlF,QAAQE,IAAMuW,EAAarV,MAAMsF,YAAY7G,GAAK8G,EAAmB,EAAI,IAExGD,EAAY7G,EAAI5H,KAAKiN,UAAUC,GAAKsR,EAAarV,MAAMsF,YAAY7G,GAAK8G,EAAmB,EAAI,MAGjGoQ,EAAiB9e,KAAKiN,UAAUC,GAAK4R,EACrCrQ,EAAY7G,EAAI4W,EAAa3R,MAAM4B,YAAY7G,GAAK8G,EAAmBqQ,EAAc,GAIlD,UAAhCP,EAAa3R,MAAMO,SACpBqB,EAAY5G,EAAI6G,EAAmB1O,KAAKiN,UAAUlF,QAAQK,KAAOoW,EAAa3R,MAAM4B,YAAY5G,EAAI7H,KAAKiN,UAAUpC,GAAK,GAExH4D,EAAY5G,EAAI7H,KAAKiN,UAAUnC,GAAK0T,EAAa3R,MAAM4B,YAAY5G,EAAI,IAIxE4W,EAAYO,UACb/e,EAASoN,WAAWyR,EAAgBjb,EAAO7D,KAAMA,KAAKoe,WAAYpe,KAAKiN,UAAUjN,KAAK6N,aAAae,OAAQP,GACzGmQ,EAAaS,WAAWC,KACxBV,EAAaS,WAAWjf,KAAK2N,MAAMwR,MAClC1R,GAGFgR,EAAYW,WACbnf,EAASsO,YAAYuQ,EAAgBC,EAAalb,EAAO+a,EAAa5e,KAAMye,EAAYrV,OAAQqF,EAAa8P,GAC3GC,EAAaS,WAAWI,MACxBb,EAAaS,WAAWjf,KAAK2N,MAAMwR,KACT,UAAzBV,EAAYrR,SAAuBoR,EAAaS,WAAWR,EAAYrR,UAAYoR,EAAaS,WAAgB,KAChHvQ,EAAkBjB,KAEvByH,KAAKlV,OAlGT,GAAIie,IACFpW,GACE+F,IAAK,IACLgB,IAAK,QACLuQ,IAAK,aACLhB,UAAW,KACXD,QAAS,KACTG,WAAY,MAEdzW,GACEgG,IAAK,IACLgB,IAAK,SACLuQ,IAAK,WACLhB,UAAW,KACXD,QAAS,KACTG,WAAY,MAsFhBpe,GAAS8d,KAAO9d,EAASyT,MAAM1S,QAC7BiT,YAAa8J,EACbO,oBAAqBA,EACrBK,aAAc,SAAS3c,EAAO6B,EAAOc,GACnC,KAAM,IAAIoH,OAAM,uCAIpB9L,EAAS8d,KAAKpQ,MAAQsQ,GAEtB9d,OAAQC,SAAUH,GAuBnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEA,SAASqf,GAAcC,EAAU5a,EAAMsI,EAAWhE,GAEhD,GAAIQ,GAAUR,EAAQQ,SAAWxJ,EAASoJ,WAAW1E,EAAMsE,EAASsW,EAAS3R,IAC7E5N,MAAK8I,OAAS7I,EAAS8K,UAAUkC,EAAUsS,EAASrB,SAAWjR,EAAUsS,EAASpB,WAAY1U,EAASR,EAAQ+B,eAAiB,GAAI/B,EAAQgC,aAC5IjL,KAAK+I,OACHkB,IAAKjK,KAAK8I,OAAOmB,IACjBxG,IAAKzD,KAAK8I,OAAOrF,KAGnBxD,EAASqf,cAATrf,SAA6BgU,YAAYtO,KAAK3F,KAC5Cuf,EACAtS,EACAjN,KAAK8I,OAAOkD,OACZ/C,GAGJ,QAAS0V,GAAa3c,GACpB,MAAOhC,MAAK6I,aAAe5I,EAASqK,cAActI,EAAOhC,KAAK2N,MAAMC,KAAO5N,KAAK8I,OAAOmB,KAAOjK,KAAK8I,OAAOC,MAG5G9I,EAASqf,cAAgBrf,EAAS8d,KAAK/c,QACrCiT,YAAaqL,EACbX,aAAcA,KAGhBxe,OAAQC,SAAUH,GAqBnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEA,SAASuf,GAAeD,EAAU5a,EAAMsI,EAAWhE,GACjD,GAAIQ,GAAUR,EAAQQ,SAAWxJ,EAASoJ,WAAW1E,EAAMsE,EAASsW,EAAS3R,IAC7E5N,MAAK4K,QAAU3B,EAAQ2B,SAAW,EAClC5K,KAAKge,MAAQ/U,EAAQ+U,OAAS/d,EAASyC,MAAM1C,KAAK4K,SAASlH,IAAI,SAAS1B,EAAO6B,GAC7E,MAAO4F,GAAQG,KAAOH,EAAQC,KAAOD,EAAQG,KAAO5J,KAAK4K,QAAU/G,GACnEqR,KAAKlV,OACPA,KAAKge,MAAMyB,KAAK,SAAS3B,EAAG4B,GAC1B,MAAO5B,GAAI4B,IAEb1f,KAAK+I,OACHkB,IAAKR,EAAQG,IACbnG,IAAKgG,EAAQC,MAGfzJ,EAASuf,eAATvf,SAA8BgU,YAAYtO,KAAK3F,KAC7Cuf,EACAtS,EACAjN,KAAKge,MACL/U,GAEFjJ,KAAK2f,WAAa3f,KAAK6I,WAAa7I,KAAK4K,QAG3C,QAAS+T,GAAa3c,GACpB,MAAOhC,MAAK6I,aAAe5I,EAASqK,cAActI,EAAOhC,KAAK2N,MAAMC,KAAO5N,KAAK+I,MAAMkB,MAAQjK,KAAK+I,MAAMtF,IAAMzD,KAAK+I,MAAMkB,KAG5HhK,EAASuf,eAAiBvf,EAAS8d,KAAK/c,QACtCiT,YAAauL,EACbb,aAAcA,KAGhBxe,OAAQC,SAAUH,GAiBnB,SAAUE,EAAQC,EAAUH,GAC3B,YAEA,SAAS2f,GAASL,EAAU5a,EAAMsI,EAAWhE,GAC3ChJ,EAAS2f,SAAT3f,SAAwBgU,YAAYtO,KAAK3F,KACvCuf,EACAtS,EACAhE,EAAQ+U,MACR/U,EAEF,IAAI4W,GAAOrc,KAAKC,IAAI,EAAGwF,EAAQ+U,MAAM1c,QAAU2H,EAAQ6W,QAAU,EAAI,GACrE9f,MAAK2f,WAAa3f,KAAK6I,WAAagX,EAGtC,QAASlB,GAAa3c,EAAO6B,GAC3B,MAAO7D,MAAK2f,WAAa9b,EAG3B5D,EAAS2f,SAAW3f,EAAS8d,KAAK/c,QAChCiT,YAAa2L,EACbjB,aAAcA,KAGhBxe,OAAQC,SAAUH,GASnB,SAASE,EAAQC,EAAUH,GAC1B,YA0GA,SAASwU,GAAYxL,GACnB,GAAItE,GAAO1E,EAASqG,cAActG,KAAK2E,KAAMsE,EAAQ/B,aAAa,EAGlElH,MAAKM,IAAML,EAASmF,UAAUpF,KAAKqF,UAAW4D,EAAQ3D,MAAO2D,EAAQ1D,OAAQ0D,EAAQgW,WAAWc,MAEhG,IAKI5W,GAAO0D,EALPwB,EAAYrO,KAAKM,IAAIyN,KAAK,KAAK7H,SAAS+C,EAAQgW,WAAW5Q,WAC3D2R,EAAchgB,KAAKM,IAAIyN,KAAK,KAC5BwQ,EAAave,KAAKM,IAAIyN,KAAK,KAAK7H,SAAS+C,EAAQgW,WAAWV,YAE5DtR,EAAYhN,EAASyM,gBAAgB1M,KAAKM,IAAK2I,EAASuH,EAAezI,QAIzEoB,GADwB7G,SAAvB2G,EAAQE,MAAM+E,KACP,GAAIjO,GAAS2f,SAAS3f,EAAS8d,KAAKpQ,MAAM9F,EAAGlD,EAAKiC,WAAWC,OAAQoG,EAAWhN,EAASe,UAAWiI,EAAQE,OAClH6U,MAAOrZ,EAAKiC,WAAWI,OACvB8Y,QAAS7W,EAAQgX,aAGXhX,EAAQE,MAAM+E,KAAKvI,KAAK1F,EAAUA,EAAS8d,KAAKpQ,MAAM9F,EAAGlD,EAAKiC,WAAWC,OAAQoG,EAAWhE,EAAQE,OAI5G0D,EADwBvK,SAAvB2G,EAAQ4D,MAAMqB,KACP,GAAIjO,GAASqf,cAAcrf,EAAS8d,KAAKpQ,MAAM/F,EAAGjD,EAAKiC,WAAWC,OAAQoG,EAAWhN,EAASe,UAAWiI,EAAQ4D,OACvHnD,KAAMzJ,EAASiK,UAAUjB,EAAQS,MAAQT,EAAQS,KAAOT,EAAQ4D,MAAMnD,KACtEE,IAAK3J,EAASiK,UAAUjB,EAAQW,KAAOX,EAAQW,IAAMX,EAAQ4D,MAAMjD,OAG7DX,EAAQ4D,MAAMqB,KAAKvI,KAAK1F,EAAUA,EAAS8d,KAAKpQ,MAAM/F,EAAGjD,EAAKiC,WAAWC,OAAQoG,EAAWhE,EAAQ4D,OAG9G1D,EAAMmV,oBAAoBjQ,EAAWkQ,EAAYve,KAAKsV,sBAAuBrM,EAASjJ,KAAKyN,cAC3FZ,EAAMyR,oBAAoBjQ,EAAWkQ,EAAYve,KAAKsV,sBAAuBrM,EAASjJ,KAAKyN,cAEvFxE,EAAQiX,oBACVjgB,EAASmO,qBAAqBC,EAAWpB,EAAWhE,EAAQgW,WAAW3Q,eAAgBtO,KAAKyN,cAI9F9I,EAAKgC,IAAIE,OAAOjD,QAAQ,SAASiD,EAAQsZ,GACvC,GAAIC,GAAgBJ,EAAYjS,KAAK,IAGrCqS,GAAcna,MACZoa,iBAAkBxZ,EAAOuI,KACzBkR,UAAWrgB,EAASyE,UAAUmC,EAAOyB,QAIvC8X,EAAcla,UACZ+C,EAAQgW,WAAWpY,OAClBA,EAAOrB,WAAayD,EAAQgW,WAAWpY,OAAS,IAAM5G,EAASY,cAAcsf,IAC9EnS,KAAK,KAEP,IAAIsC,MACFiQ,IAEF5b,GAAKiC,WAAWC,OAAOsZ,GAAavc,QAAQ,SAAS5B,EAAOwe,GAC1D,GAAI/V,IACF5C,EAAGoF,EAAUpC,GAAK1B,EAAMwV,aAAa3c,EAAOwe,EAAY7b,EAAKiC,WAAWC,OAAOsZ,IAC/EvY,EAAGqF,EAAUC,GAAKL,EAAM8R,aAAa3c,EAAOwe,EAAY7b,EAAKiC,WAAWC,OAAOsZ,IAEjF7P,GAAgBrJ,KAAKwD,EAAE5C,EAAG4C,EAAE7C,GAC5B2Y,EAAStZ,MACPjF,MAAOA,EACPwe,WAAYA,EACZlY,KAAMrI,EAASoI,YAAYxB,EAAQ2Z,MAErCtL,KAAKlV,MAEP,IAAIqP,IACFoR,WAAYxgB,EAASkP,gBAAgBtI,EAAQoC,EAAS,cACtDyX,UAAWzgB,EAASkP,gBAAgBtI,EAAQoC,EAAS,aACrD0X,SAAU1gB,EAASkP,gBAAgBtI,EAAQoC,EAAS,YACpD2X,SAAU3gB,EAASkP,gBAAgBtI,EAAQoC,EAAS,YACpD4X,SAAU5gB,EAASkP,gBAAgBtI,EAAQoC,EAAS,aAGlD6X,EAAgD,kBAA7BzR,GAAcoR,WACnCpR,EAAcoR,WAAcpR,EAAcoR,WAAaxgB,EAAS4Q,cAAcuB,gBAAkBnS,EAAS4Q,cAAcC,OAGrHC,EAAO+P,EAAUxQ,EAAiBiQ,EAmCtC,IA9BIlR,EAAcqR,WAEhB3P,EAAKyK,aAAa5X,QAAQ,SAAS8X,GACjC,GAAIqF,GAAQX,EAAcrS,KAAK,QAC7BlD,GAAI6Q,EAAY7T,EAChBqF,GAAIwO,EAAY9T,EAChBkD,GAAI4Q,EAAY7T,EAAI,IACpBsF,GAAIuO,EAAY9T,GACfqB,EAAQgW,WAAW8B,OAAO9a,MAC3B+a,YAAatF,EAAY/W,KAAK3C,MAAM6F,EAAG6T,EAAY/W,KAAK3C,MAAM4F,GAAG/B,OAAO5F,EAASiK,WAAW8D,KAAK,KACjGsS,UAAWrgB,EAASyE,UAAUgX,EAAY/W,KAAK2D,OAGjDtI,MAAKyN,aAAaQ,KAAK,QACrBC,KAAM,QACNlM,MAAO0Z,EAAY/W,KAAK3C,MACxB6B,MAAO6X,EAAY/W,KAAK6b,WACxBlY,KAAMoT,EAAY/W,KAAK2D,KACvBzB,OAAQA,EACRsZ,YAAaA,EACbhX,MAAOA,EACP0D,MAAOA,EACPU,MAAO6S,EACPjS,QAAS4S,EACTlZ,EAAG6T,EAAY7T,EACfD,EAAG8T,EAAY9T,KAEjBsN,KAAKlV,OAGNqP,EAAcsR,SAAU,CACzB,GAAItP,GAAO+O,EAAcrS,KAAK,QAC5BwD,EAAGR,EAAKlM,aACPoE,EAAQgW,WAAW5N,MAAM,EAE5BrR,MAAKyN,aAAaQ,KAAK,QACrBC,KAAM,OACNlC,OAAQrH,EAAKiC,WAAWC,OAAOsZ,GAC/BpP,KAAMA,EAAKyM,QACXvQ,UAAWA,EACXpJ,MAAOsc,EACPtZ,OAAQA,EACRsZ,YAAaA,EACbc,WAAYpa,EAAOyB,KACnBa,MAAOA,EACP0D,MAAOA,EACPU,MAAO6S,EACPjS,QAASkD,IAKb,GAAGhC,EAAcuR,UAAY/T,EAAM9D,MAAO,CAGxC,GAAI8X,GAAWrd,KAAKC,IAAID,KAAKyG,IAAIoF,EAAcwR,SAAUhU,EAAM9D,MAAMtF,KAAMoJ,EAAM9D,MAAMkB,KAGnFiX,EAAoBjU,EAAUC,GAAKL,EAAM8R,aAAakC,EAG1D9P,GAAK0M,eAAe,KAAK5X,OAAO,SAA2Bsb,GAEzD,MAAOA,GAAY3F,aAAala,OAAS,IACxCoC,IAAI,SAAuB0d,GAE5B,GAAIC,GAAeD,EAAkB5F,aAAa,GAC9C8F,EAAcF,EAAkB5F,aAAa4F,EAAkB5F,aAAala,OAAS,EAMzF,OAAO8f,GAAkB5D,OAAM,GAC5BpQ,SAAS,GACTiK,OAAO,GACPjG,KAAKiQ,EAAaxZ,EAAGqZ,GACrB7P,KAAKgQ,EAAaxZ,EAAGwZ,EAAazZ,GAClCwF,SAASgU,EAAkB5F,aAAala,OAAS,GACjD+P,KAAKiQ,EAAYzZ,EAAGqZ,KAEtBtd,QAAQ,SAAoB2d,GAG7B,GAAIC,GAAOpB,EAAcrS,KAAK,QAC5BwD,EAAGgQ,EAAS1c,aACXoE,EAAQgW,WAAWuC,MAAM,EAG5BxhB,MAAKyN,aAAaQ,KAAK,QACrBC,KAAM,OACNlC,OAAQrH,EAAKiC,WAAWC,OAAOsZ,GAC/BpP,KAAMwQ,EAAS/D,QACf3W,OAAQA,EACRsZ,YAAaA,EACbhX,MAAOA,EACP0D,MAAOA,EACPI,UAAWA,EACXpJ,MAAOsc,EACP5S,MAAO6S,EACPjS,QAASqT,KAEXtM,KAAKlV,SAETkV,KAAKlV,OAEPA,KAAKyN,aAAaQ,KAAK,WACrBnF,OAAQ+D,EAAM/D,OACdmE,UAAWA,EACX9D,MAAOA,EACP0D,MAAOA,EACPvM,IAAKN,KAAKM,IACV2I,QAASA,IAqFb,QAASwY,GAAKjf,EAAOmC,EAAMsE,EAASsG,GAClCtP,EAASwhB,KAATxhB,SAAoBgU,YAAYtO,KAAK3F,KACnCwC,EACAmC,EACA6L,EACAvQ,EAASe,UAAWwP,EAAgBvH,GACpCsG,GArYJ,GAAIiB,IAEFrH,OAEEC,OAAQ,GAERgE,SAAU,MAEVqB,aACE5G,EAAG,EACHD,EAAG,GAGLwX,WAAW,EAEXJ,UAAU,EAEVH,sBAAuB5e,EAASU,KAEhCuN,KAAM5L,QAGRuK,OAEEzD,OAAQ,GAERgE,SAAU,QAEVqB,aACE5G,EAAG,EACHD,EAAG,GAGLwX,WAAW,EAEXJ,UAAU,EAEVH,sBAAuB5e,EAASU,KAEhCuN,KAAM5L,OAEN0I,cAAe,GAEfC,aAAa,GAGf3F,MAAOhD,OAEPiD,OAAQjD,OAERqe,UAAU,EAEVD,WAAW,EAEXE,UAAU,EAEVC,SAAU,EAEVJ,YAAY,EAEZP,oBAAoB,EAEpBtW,IAAKtH,OAELoH,KAAMpH,OAEN4G,cACEjB,IAAK,GACLC,MAAO,GACPC,OAAQ,EACRC,KAAM,IAGR6X,WAAW,EAEX/Y,aAAa,EAEb+X,YACEc,MAAO,gBACPV,MAAO,WACPd,WAAY,YACZ1X,OAAQ,YACRwK,KAAM,UACN0P,MAAO,WACPS,KAAM,UACNtC,KAAM,UACN7Q,UAAW,WACXC,eAAgB,qBAChBoT,SAAU,cACVC,WAAY,gBACZC,MAAO,WACPC,IAAK,UA8ST5hB,GAASwhB,KAAOxhB,EAASoV,KAAKrU,QAC5BiT,YAAawN,EACbhN,YAAaA,KAGftU,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA0GA,SAASwU,GAAYxL,GACnB,GAAItE,GACA8E,CAEDR,GAAQ6Y,kBACTnd,EAAO1E,EAASqG,cAActG,KAAK2E,KAAMsE,EAAQ/B,YAAa+B,EAAQ8Y,eAAiB,IAAM,KAC7Fpd,EAAKiC,WAAWC,OAASlC,EAAKiC,WAAWC,OAAOnD,IAAI,SAAS1B,GAC3D,OAAQA,MAGV2C,EAAO1E,EAASqG,cAActG,KAAK2E,KAAMsE,EAAQ/B,YAAa+B,EAAQ8Y,eAAiB,IAAM,KAI/F/hB,KAAKM,IAAML,EAASmF,UAClBpF,KAAKqF,UACL4D,EAAQ3D,MACR2D,EAAQ1D,OACR0D,EAAQgW,WAAWc,OAAS9W,EAAQ8Y,eAAiB,IAAM9Y,EAAQgW,WAAW8C,eAAiB,IAIjG,IAAI1T,GAAYrO,KAAKM,IAAIyN,KAAK,KAAK7H,SAAS+C,EAAQgW,WAAW5Q,WAC3D2R,EAAchgB,KAAKM,IAAIyN,KAAK,KAC5BwQ,EAAave,KAAKM,IAAIyN,KAAK,KAAK7H,SAAS+C,EAAQgW,WAAWV,WAEhE,IAAGtV,EAAQ+Y,WAA+C,IAAlCrd,EAAKiC,WAAWC,OAAOvF,OAAc,CAG3D,GAAI2gB,GAAahiB,EAASmD,UAAUuB,EAAKiC,WAAWC,OAAQ;AAC1D,MAAOrF,OAAMiE,UAAUC,MAAMC,KAAKtE,WAAWqC,IAAI,SAAS1B,GACxD,MAAOA,KACNgD,OAAO,SAASkd,EAAMC,GACvB,OACEta,EAAGqa,EAAKra,GAAKsa,GAAQA,EAAKta,IAAM,EAChCD,EAAGsa,EAAKta,GAAKua,GAAQA,EAAKva,IAAM,KAEhCC,EAAG,EAAGD,EAAG,KAGf6B,GAAUxJ,EAASoJ,YAAY4Y,GAAahZ,EAASA,EAAQ8Y,eAAiB,IAAM,SAIpFtY,GAAUxJ,EAASoJ,WAAW1E,EAAKiC,WAAWC,OAAQoC,EAASA,EAAQ8Y,eAAiB,IAAM,IAIhGtY,GAAQC,MAAQT,EAAQS,OAA0B,IAAjBT,EAAQS,KAAa,EAAID,EAAQC,MAClED,EAAQG,KAAOX,EAAQW,MAAwB,IAAhBX,EAAQW,IAAY,EAAIH,EAAQG,IAE/D,IAEIwY,GACFC,EACAC,EACAnZ,EACA0D,EANEI,EAAYhN,EAASyM,gBAAgB1M,KAAKM,IAAK2I,EAASuH,EAAezI,QAYzEsa,GAHCpZ,EAAQ6Y,kBAAoB7Y,EAAQ+Y,UAGpBrd,EAAKiC,WAAWI,OAAOtB,MAAM,EAAG,GAKhCf,EAAKiC,WAAWI,OAIhCiC,EAAQ8Y,gBAEPK,EAAYjZ,EADY7G,SAAvB2G,EAAQE,MAAM+E,KACK,GAAIjO,GAASqf,cAAcrf,EAAS8d,KAAKpQ,MAAM9F,EAAGlD,EAAKiC,WAAWC,OAAQoG,EAAWhN,EAASe,UAAWiI,EAAQE,OACnIM,QAASA,EACTO,eAAgB,KAGEf,EAAQE,MAAM+E,KAAKvI,KAAK1F,EAAUA,EAAS8d,KAAKpQ,MAAM9F,EAAGlD,EAAKiC,WAAWC,OAAQoG,EAAWhN,EAASe,UAAWiI,EAAQE,OAC1IM,QAASA,EACTO,eAAgB,KAKlBsY,EAAYzV,EADYvK,SAAvB2G,EAAQ4D,MAAMqB,KACK,GAAIjO,GAAS2f,SAAS3f,EAAS8d,KAAKpQ,MAAM/F,EAAGjD,EAAKiC,WAAWC,OAAQoG,GACvF+Q,MAAOqE,IAGWpZ,EAAQ4D,MAAMqB,KAAKvI,KAAK1F,EAAUA,EAAS8d,KAAKpQ,MAAM/F,EAAGjD,EAAKiC,WAAWC,OAAQoG,EAAWhE,EAAQ4D,SAIxHyV,EAAYnZ,EADY7G,SAAvB2G,EAAQE,MAAM+E,KACK,GAAIjO,GAAS2f,SAAS3f,EAAS8d,KAAKpQ,MAAM9F,EAAGlD,EAAKiC,WAAWC,OAAQoG,GACvF+Q,MAAOqE,IAGWpZ,EAAQE,MAAM+E,KAAKvI,KAAK1F,EAAUA,EAAS8d,KAAKpQ,MAAM9F,EAAGlD,EAAKiC,WAAWC,OAAQoG,EAAWhE,EAAQE,OAIxHiZ,EAAYvV,EADYvK,SAAvB2G,EAAQ4D,MAAMqB,KACK,GAAIjO,GAASqf,cAAcrf,EAAS8d,KAAKpQ,MAAM/F,EAAGjD,EAAKiC,WAAWC,OAAQoG,EAAWhN,EAASe,UAAWiI,EAAQ4D,OACnIpD,QAASA,EACTO,eAAgB,KAGEf,EAAQ4D,MAAMqB,KAAKvI,KAAK1F,EAAUA,EAAS8d,KAAKpQ,MAAM/F,EAAGjD,EAAKiC,WAAWC,OAAQoG,EAAWhN,EAASe,UAAWiI,EAAQ4D,OAC1IpD,QAASA,EACTO,eAAgB,KAMtB,IAAIuY,GAAYtZ,EAAQ8Y,eAAkB9U,EAAUpC,GAAKuX,EAAUzD,aAAa,GAAO1R,EAAUC,GAAKkV,EAAUzD,aAAa,GAEzH6D,IAEJF,GAAUhE,oBAAoBjQ,EAAWkQ,EAAYve,KAAKsV,sBAAuBrM,EAASjJ,KAAKyN,cAC/F2U,EAAU9D,oBAAoBjQ,EAAWkQ,EAAYve,KAAKsV,sBAAuBrM,EAASjJ,KAAKyN,cAE3FxE,EAAQiX,oBACVjgB,EAASmO,qBAAqBC,EAAWpB,EAAWhE,EAAQgW,WAAW3Q,eAAgBtO,KAAKyN,cAI9F9I,EAAKgC,IAAIE,OAAOjD,QAAQ,SAASiD,EAAQsZ,GAEvC,GAEIsC,GAEArC,EAJAsC,EAAQvC,GAAexb,EAAKgC,IAAIE,OAAOvF,OAAS,GAAK,CAUvDmhB,GAHCxZ,EAAQ6Y,mBAAqB7Y,EAAQ+Y,UAGnBM,EAAUzZ,WAAalE,EAAKiC,WAAWC,OAAOvF,OAAS,EAClE2H,EAAQ6Y,kBAAoB7Y,EAAQ+Y,UAGzBM,EAAUzZ,WAAa,EAGvByZ,EAAUzZ,WAAalE,EAAKiC,WAAWC,OAAOsZ,GAAa7e,OAAS,EAIzF8e,EAAgBJ,EAAYjS,KAAK,KAGjCqS,EAAcna,MACZoa,iBAAkBxZ,EAAOuI,KACzBkR,UAAWrgB,EAASyE,UAAUmC,EAAOyB,QAIvC8X,EAAcla,UACZ+C,EAAQgW,WAAWpY,OAClBA,EAAOrB,WAAayD,EAAQgW,WAAWpY,OAAS,IAAM5G,EAASY,cAAcsf,IAC9EnS,KAAK,MAEPrJ,EAAKiC,WAAWC,OAAOsZ,GAAavc,QAAQ,SAAS5B,EAAOwe,GAC1D,GAAImC,GACFC,EACAC,EACAC,CA+CF,IAzCEA,EAHC7Z,EAAQ6Y,mBAAqB7Y,EAAQ+Y,UAGhB7B,EACdlX,EAAQ6Y,kBAAoB7Y,EAAQ+Y,UAGtB,EAGAxB,EAKtBmC,EADC1Z,EAAQ8Y,gBAEPla,EAAGoF,EAAUpC,GAAKuX,EAAUzD,aAAa3c,GAASA,EAAM6F,EAAI7F,EAAM6F,EAAI,EAAG2Y,EAAY7b,EAAKiC,WAAWC,OAAOsZ,IAC5GvY,EAAGqF,EAAUC,GAAKoV,EAAU3D,aAAa3c,GAASA,EAAM4F,EAAI5F,EAAM4F,EAAI,EAAGkb,EAAqBne,EAAKiC,WAAWC,OAAOsZ,MAIrHtY,EAAGoF,EAAUpC,GAAKyX,EAAU3D,aAAa3c,GAASA,EAAM6F,EAAI7F,EAAM6F,EAAI,EAAGib,EAAqBne,EAAKiC,WAAWC,OAAOsZ,IACrHvY,EAAGqF,EAAUC,GAAKkV,EAAUzD,aAAa3c,GAASA,EAAM4F,EAAI5F,EAAM4F,EAAI,EAAG4Y,EAAY7b,EAAKiC,WAAWC,OAAOsZ,KAQ7GmC,YAAqBriB,GAAS2f,WAE3B0C,EAAUrZ,QAAQ6W,UACpB6C,EAAUL,EAAU3U,MAAMC,MAAQ6U,GAAoBxZ,EAAQ8Y,kBAAsB,IAGtFY,EAAUL,EAAU3U,MAAMC,MAAS3E,EAAQ+Y,WAAa/Y,EAAQ6Y,iBAAoB,EAAIY,EAAQzZ,EAAQ8Z,mBAAqB9Z,EAAQ8Y,kBAAsB,IAI7Jc,EAAgBL,EAAiBhC,IAAe+B,EAChDC,EAAiBhC,GAAcqC,GAAiBN,EAAYI,EAAUL,EAAUzU,aAAaD,MAGhFtL,SAAVN,EAAH,CAIA,GAAIghB,KACJA,GAAUV,EAAU3U,MAAMC,IAAM,KAAO+U,EAAUL,EAAU3U,MAAMC,KACjEoV,EAAUV,EAAU3U,MAAMC,IAAM,KAAO+U,EAAUL,EAAU3U,MAAMC,MAE9D3E,EAAQ+Y,WAAoC,eAAtB/Y,EAAQga,WAA+Bha,EAAQga,WAUtED,EAAUV,EAAUzU,aAAaD,IAAM,KAAO2U,EAC9CS,EAAUV,EAAUzU,aAAaD,IAAM,KAAO+U,EAAUL,EAAUzU,aAAaD,OAN/EoV,EAAUV,EAAUzU,aAAaD,IAAM,KAAOiV,EAC9CG,EAAUV,EAAUzU,aAAaD,IAAM,KAAO4U,EAAiBhC,IASjEwC,EAAUnY,GAAKrH,KAAKyG,IAAIzG,KAAKC,IAAIuf,EAAUnY,GAAIoC,EAAUpC,IAAKoC,EAAUnC,IACxEkY,EAAUlY,GAAKtH,KAAKyG,IAAIzG,KAAKC,IAAIuf,EAAUlY,GAAImC,EAAUpC,IAAKoC,EAAUnC,IACxEkY,EAAU9V,GAAK1J,KAAKyG,IAAIzG,KAAKC,IAAIuf,EAAU9V,GAAID,EAAUE,IAAKF,EAAUC,IACxE8V,EAAU7V,GAAK3J,KAAKyG,IAAIzG,KAAKC,IAAIuf,EAAU7V,GAAIF,EAAUE,IAAKF,EAAUC,GAExE,IAAIgW,GAAWjjB,EAASoI,YAAYxB,EAAQ2Z,EAG5CoC,GAAMxC,EAAcrS,KAAK,OAAQiV,EAAW/Z,EAAQgW,WAAW2D,KAAK3c,MAClE+a,YAAahf,EAAM6F,EAAG7F,EAAM4F,GAAG/B,OAAO5F,EAASiK,WAAW8D,KAAK,KAC/DsS,UAAWrgB,EAASyE,UAAUwe,KAGhCljB,KAAKyN,aAAaQ,KAAK,OAAQhO,EAASe,QACtCkN,KAAM,MACNlM,MAAOA,EACP6B,MAAO2c,EACPlY,KAAM4a,EACNrc,OAAQA,EACRsZ,YAAaA,EACbhX,MAAOA,EACP0D,MAAOA,EACPI,UAAWA,EACXM,MAAO6S,EACPjS,QAASyU,GACRI,MACH9N,KAAKlV,QACPkV,KAAKlV,OAEPA,KAAKyN,aAAaQ,KAAK,WACrBnF,OAAQsZ,EAAUtZ,OAClBmE,UAAWA,EACX9D,MAAOA,EACP0D,MAAOA,EACPvM,IAAKN,KAAKM,IACV2I,QAASA,IAyCb,QAASka,GAAI3gB,EAAOmC,EAAMsE,EAASsG,GACjCtP,EAASkjB,IAATljB,SAAmBgU,YAAYtO,KAAK3F,KAClCwC,EACAmC,EACA6L,EACAvQ,EAASe,UAAWwP,EAAgBvH,GACpCsG,GAnaJ,GAAIiB,IAEFrH,OAEEC,OAAQ,GAERgE,SAAU,MAEVqB,aACE5G,EAAG,EACHD,EAAG,GAGLwX,WAAW,EAEXJ,UAAU,EAEVH,sBAAuB5e,EAASU,KAEhCqK,cAAe,GAEfC,aAAa,GAGf4B,OAEEzD,OAAQ,GAERgE,SAAU,QAEVqB,aACE5G,EAAG,EACHD,EAAG,GAGLwX,WAAW,EAEXJ,UAAU,EAEVH,sBAAuB5e,EAASU,KAEhCqK,cAAe,GAEfC,aAAa,GAGf3F,MAAOhD,OAEPiD,OAAQjD,OAERoH,KAAMpH,OAENsH,IAAKtH,OAEL0H,eAAgB,EAEhBd,cACEjB,IAAK,GACLC,MAAO,GACPC,OAAQ,EACRC,KAAM,IAGR2a,kBAAmB,GAEnBf,WAAW,EAGXiB,UAAW,aAEXlB,gBAAgB,EAEhBD,kBAAkB,EAElB5a,aAAa,EAEbgZ,oBAAoB,EAEpBjB,YACEc,MAAO,eACPgC,eAAgB,qBAChB1C,MAAO,WACPd,WAAY,YACZ1X,OAAQ,YACR+b,IAAK,SACL1D,KAAM,UACN7Q,UAAW,WACXC,eAAgB,qBAChBoT,SAAU,cACVC,WAAY,gBACZC,MAAO,WACPC,IAAK,UA4UT5hB,GAASkjB,IAAMljB,EAASoV,KAAKrU,QAC3BiT,YAAakP,EACb1O,YAAaA,KAGftU,OAAQC,SAAUH,GAOnB,SAASE,EAAQC,EAAUH,GAC1B,YA2DA,SAASmjB,GAAwBC,EAAQhE,EAAOiE,GAC9C,GAAIC,GAAalE,EAAMxX,EAAIwb,EAAOxb,CAElC,OAAG0b,IAA4B,YAAdD,IACdC,GAA4B,YAAdD,EACR,QACCC,GAA4B,YAAdD,IACrBC,GAA4B,YAAdD,EACR,MAEA,SASX,QAAS7O,GAAYxL,GACnB,GAEEua,GACAvW,EACAb,EACAqX,EACAC,EANE/e,EAAO1E,EAASqG,cAActG,KAAK2E,MACnCgf,KAMFC,EAAa3a,EAAQ2a,UAGvB5jB,MAAKM,IAAML,EAASmF,UAAUpF,KAAKqF,UAAW4D,EAAQ3D,MAAO2D,EAAQ1D,OAAO0D,EAAQ4a,MAAQ5a,EAAQgW,WAAW6E,WAAa7a,EAAQgW,WAAW8E,UAE/I9W,EAAYhN,EAASyM,gBAAgB1M,KAAKM,IAAK2I,EAASuH,EAAezI,SAEvEqE,EAAS5I,KAAKyG,IAAIgD,EAAU3H,QAAU,EAAG2H,EAAU1H,SAAW,GAE9Dme,EAAeza,EAAQ+a,OAASrf,EAAKiC,WAAWC,OAAO7B,OAAO,SAASif,EAAeC,GACpF,MAAOD,GAAgBC,GACtB,EAEH,IAAIC,GAAalkB,EAASiC,SAAS+G,EAAQkb,WACnB,OAApBA,EAAWliB,OACbkiB,EAAWniB,OAASoK,EAAS,KAM/BA,GAAUnD,EAAQ4a,QAAU5a,EAAQmb,WAAaD,EAAWniB,MAAQ,EAAK,EAKvEyhB,EAD2B,YAA1Bxa,EAAQob,eAA+Bpb,EAAQ4a,QAAU5a,EAAQmb,WACpDhY,EACoB,WAA1BnD,EAAQob,cAEF,EACNpb,EAAQmb,WACFhY,EAAS+X,EAAWniB,MAAQ,EAI5BoK,EAAS,EAGzBqX,GAAexa,EAAQwF,WAGvB,IAAI4U,IACFxb,EAAGoF,EAAUpC,GAAKoC,EAAU3H,QAAU,EACtCsC,EAAGqF,EAAUE,GAAKF,EAAU1H,SAAW,GAIrC+e,EAEU,IAFa3f,EAAKgC,IAAIE,OAAOhB,OAAO,SAAS0e,GACzD,MAAOA,GAAIjd,eAAe,SAAyB,IAAdid,EAAIviB,MAAsB,IAARuiB,IACtDjjB,MAGHqD,GAAKgC,IAAIE,OAAOjD,QAAQ,SAASiD,EAAQhD,GACvC8f,EAAa9f,GAAS7D,KAAKM,IAAIyN,KAAK,IAAK,KAAM,OAC/CmH,KAAKlV,OAEJiJ,EAAQmW,YACToE,EAAcxjB,KAAKM,IAAIyN,KAAK,IAAK,KAAM,OAKzCpJ,EAAKgC,IAAIE,OAAOjD,QAAQ,SAASiD,EAAQhD,GAEvC,GAAsC,IAAlCc,EAAKiC,WAAWC,OAAOhD,KAAgBoF,EAAQub,kBAAnD,CAGAb,EAAa9f,GAAOoC,MAClBoa,iBAAkBxZ,EAAOuI,OAI3BuU,EAAa9f,GAAOqC,UAClB+C,EAAQgW,WAAWpY,OAClBA,EAAOrB,WAAayD,EAAQgW,WAAWpY,OAAS,IAAM5G,EAASY,cAAcgD,IAC9EmK,KAAK,KAGP,IAAIyW,GAAYf,EAAe,EAAIE,EAAajf,EAAKiC,WAAWC,OAAOhD,GAAS6f,EAAe,IAAM,EAGjGgB,EAAuBlhB,KAAKC,IAAI,EAAGmgB,GAAwB,IAAV/f,GAAeygB,EAAuB,EAAI,IAI5FG,GAAWC,GAAwB,SACpCD,EAAWC,EAAuB,OAGpC,IAGIC,GACFC,EACAC,EALEjD,EAAQ3hB,EAASgM,iBAAiBoX,EAAOxb,EAAGwb,EAAOzb,EAAGwE,EAAQsY,GAChE7C,EAAM5hB,EAASgM,iBAAiBoX,EAAOxb,EAAGwb,EAAOzb,EAAGwE,EAAQqY,GAO1D1T,EAAO,GAAI9Q,GAAS+F,IAAIgL,MAAM/H,EAAQ4a,OAAS5a,EAAQmb,YACxDhT,KAAKyQ,EAAIha,EAAGga,EAAIja,GAChBwU,IAAIhQ,EAAQA,EAAQ,EAAGqY,EAAWb,EAAa,IAAK,EAAGhC,EAAM/Z,EAAG+Z,EAAMha,EAGrEqB,GAAQ4a,MAED5a,EAAQmb,aACjBS,EAAmBzY,EAAS+X,EAAWniB,MACvC2iB,EAAa1kB,EAASgM,iBAAiBoX,EAAOxb,EAAGwb,EAAOzb,EAAGid,EAAkBjB,GAAwB,IAAV/f,GAAeygB,EAAuB,EAAI,KACrIM,EAAW3kB,EAASgM,iBAAiBoX,EAAOxb,EAAGwb,EAAOzb,EAAGid,EAAkBJ,GAC3E1T,EAAKM,KAAKsT,EAAW9c,EAAG8c,EAAW/c,GACnCmJ,EAAKqL,IAAIyI,EAAkBA,EAAkB,EAAGJ,EAAWb,EAAc,IAAK,EAAGgB,EAAS/c,EAAG+c,EAAShd,IANtGmJ,EAAKM,KAAKgS,EAAOxb,EAAGwb,EAAOzb,EAW7B,IAAIkd,GAAgB7b,EAAQgW,WAAW8F,QACnC9b,GAAQ4a,QACViB,EAAgB7b,EAAQgW,WAAW+F,WAC/B/b,EAAQmb,aACVU,EAAgB7b,EAAQgW,WAAWgG,iBAGvC,IAAIvJ,GAAciI,EAAa9f,GAAOkK,KAAK,QACzCwD,EAAGR,EAAKlM,aACPigB,EA+BH,IA5BApJ,EAAYzV,MACV+a,WAAYrc,EAAKiC,WAAWC,OAAOhD,GACnCyc,UAAWrgB,EAASyE,UAAUmC,EAAOyB,QAIpCW,EAAQ4a,QAAU5a,EAAQmb,aAC3B1I,EAAYvV,MAAMC,MAAM8e,YAAcf,EAAWniB,MAAQ,MAI3DhC,KAAKyN,aAAaQ,KAAK,QACrBC,KAAM,QACNlM,MAAO2C,EAAKiC,WAAWC,OAAOhD,GAC9B6f,aAAcA,EACd7f,MAAOA,EACPyE,KAAMzB,EAAOyB,KACbzB,OAAQA,EACR0G,MAAOoW,EAAa9f,GACpBsK,QAASuN,EACT3K,KAAMA,EAAKyM,QACX6F,OAAQA,EACRjX,OAAQA,EACRwX,WAAYA,EACZa,SAAUA,IAITxb,EAAQmW,UAAW,CACpB,GAAIiF,EAGFA,GAF4B,IAA3B1f,EAAKgC,IAAIE,OAAOvF,QAGfuG,EAAGwb,EAAOxb,EACVD,EAAGyb,EAAOzb,GAII3H,EAASgM,iBACvBoX,EAAOxb,EACPwb,EAAOzb,EACP6b,EACAG,GAAca,EAAWb,GAAc,EAI3C,IAAIuB,EAEFA,GADCxgB,EAAKiC,WAAWI,SAAW/G,EAASmK,gBAAgBzF,EAAKiC,WAAWI,OAAOnD,IACjEc,EAAKiC,WAAWI,OAAOnD,GAEvBc,EAAKiC,WAAWC,OAAOhD,EAGpC,IAAIuhB,GAAoBnc,EAAQ4V,sBAAsBsG,EAAUthB,EAEhE,IAAGuhB,GAA2C,IAAtBA,EAAyB,CAC/C,GAAIzW,GAAe6U,EAAYzV,KAAK,QAClCsX,GAAIhB,EAAcxc,EAClByd,GAAIjB,EAAczc,EAClB2d,cAAenC,EAAwBC,EAAQgB,EAAepb,EAAQuc,iBACrEvc,EAAQgW,WAAWI,OAAOnQ,KAAK,GAAKkW,EAGvCplB,MAAKyN,aAAaQ,KAAK,QACrBC,KAAM,QACNrK,MAAOA,EACP0J,MAAOiW,EACPrV,QAASQ,EACTO,KAAM,GAAKkW,EACXvd,EAAGwc,EAAcxc,EACjBD,EAAGyc,EAAczc,KAOvBgc,EAAaa,IACbvP,KAAKlV,OAEPA,KAAKyN,aAAaQ,KAAK,WACrBhB,UAAWA,EACX3M,IAAKN,KAAKM,IACV2I,QAASA,IAwEb,QAASwc,GAAIjjB,EAAOmC,EAAMsE,EAASsG,GACjCtP,EAASwlB,IAATxlB,SAAmBgU,YAAYtO,KAAK3F,KAClCwC,EACAmC,EACA6L,EACAvQ,EAASe,UAAWwP,EAAgBvH,GACpCsG,GA9WJ,GAAIiB,IAEFlL,MAAOhD,OAEPiD,OAAQjD,OAER4G,aAAc,EAEd+V,YACE8E,SAAU,eACVD,WAAY,iBACZjd,OAAQ,YACRke,SAAU,eACVC,WAAY,iBACZC,gBAAiB,uBACjB5F,MAAO,YAGTuE,WAAY,EAEZI,MAAO1hB,OAEPuhB,OAAO,EAEPO,YAAY,EAGZD,WAAY,GAEZ/E,WAAW,EAEX3Q,YAAa,EAEb4V,cAAe,SAEfxF,sBAAuB5e,EAASU,KAEhC6kB,eAAgB,UAEhBte,aAAa,EAEbsd,mBAAmB,EAyUrBvkB,GAASwlB,IAAMxlB,EAASoV,KAAKrU,QAC3BiT,YAAawR,EACbhR,YAAaA,EACb2O,wBAAyBA,KAG3BjjB,OAAQC,SAAUH,GAEbA","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/dist/scss/chartist.scss b/dist/scss/chartist.scss index e3caaa6b..e5c6b420 100644 --- a/dist/scss/chartist.scss +++ b/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/dist/scss/settings/_chartist-settings.scss b/dist/scss/settings/_chartist-settings.scss index 4d0370eb..def297ca 100644 --- a/dist/scss/settings/_chartist-settings.scss +++ b/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/package.json b/package.json index 6748b1d2..4126e1e9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.10.1", + "version": "0.11.0", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From 761831d86f4b1cb64c5dda06d4782e7bfa54ace4 Mon Sep 17 00:00:00 2001 From: Cayden Thalmann Date: Mon, 22 May 2017 02:06:44 -0700 Subject: [PATCH 463/593] Quick fix: fix spelling of "divisor". After this commit, the word "divisor" will be spelled correctly in the examples page. --- site/data/pages/examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/data/pages/examples.yml b/site/data/pages/examples.yml index 9d487a40..87f32f13 100644 --- a/site/data/pages/examples.yml +++ b/site/data/pages/examples.yml @@ -130,7 +130,7 @@ sections: intro: > This example uses Moment.js in the label interpolation function to format a date object. The fixed axis ensures that there is correct spacing between the data points, - and the number of labels is determined by the devisor. + and the number of labels is determined by the divisor. - title: Bar chart examples level: 3 items: From 0de4a2f2837a15365b596365d0a6d8b70526f7dd Mon Sep 17 00:00:00 2001 From: htwyford Date: Fri, 11 Aug 2017 12:07:43 -0400 Subject: [PATCH 464/593] Added targetline plugin --- bower.json | 1 + site/data/pages/plugins.yml | 24 ++++++++++++++++++++++ site/examples/example-plugin-targetline.js | 12 +++++++++++ site/layouts/default.hbs | 1 + 4 files changed, 38 insertions(+) create mode 100644 site/examples/example-plugin-targetline.js diff --git a/bower.json b/bower.json index 8da2694a..adc79afa 100755 --- a/bower.json +++ b/bower.json @@ -18,6 +18,7 @@ "chartist-plugin-threshold": "~0.0.1", "chartist-plugin-fill-donut": "~0.0.1", "chartist-plugin-zoom": "~0.2.1", + "chartist-plugin-targetline": "~1.0.0", "matchMedia": "~0.2.0", "moment": "^2.14.1" }, diff --git a/site/data/pages/plugins.yml b/site/data/pages/plugins.yml index a25c3a21..6144d15b 100755 --- a/site/data/pages/plugins.yml +++ b/site/data/pages/plugins.yml @@ -252,6 +252,30 @@ sections: - - 'Link:' - 'chartist-plugin-zoom' + - type: sub-section + data: + title: Target Line Plugin + level: 4 + items: + - type: text + data: + text: > + The target line plugin allows you to draw a target line on your chart. + - type: live-example + data: + id: example-plugin-targetline + classes: ct-golden-section + intro: > + Pass a value to the plugin to draw a target line on the chart. + - type: table + data: + rows: + - + - 'Author:' + - Harry Twyford + - + - 'Link:' + - 'chartist-plugin-targetline' - title: Develop a plugin level: 3 items: diff --git a/site/examples/example-plugin-targetline.js b/site/examples/example-plugin-targetline.js new file mode 100644 index 00000000..b6cac7e5 --- /dev/null +++ b/site/examples/example-plugin-targetline.js @@ -0,0 +1,12 @@ +new Chartist.Line('.ct-chart', { + labels: ['M', 'T', 'W', 'T', 'F'], + series: [ + [5, 11, 2, 5, 7] + ] +}, { + plugins: [ + Chartist.plugins.ctTargetLine({ + value: 6 + }) + ] +}); diff --git a/site/layouts/default.hbs b/site/layouts/default.hbs index 2bb8ee22..5e13f287 100755 --- a/site/layouts/default.hbs +++ b/site/layouts/default.hbs @@ -77,6 +77,7 @@ + From 63c727ca589501cb2468ca8a0d79bf9ea8c65253 Mon Sep 17 00:00:00 2001 From: ltlombardi Date: Thu, 20 Sep 2018 17:30:02 -0300 Subject: [PATCH 465/593] small fix Doesn't make sense to say alpha numbered, IMHO --- site/data/pages/getting-started.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/data/pages/getting-started.yml b/site/data/pages/getting-started.yml index 25591c95..d18de12d 100644 --- a/site/data/pages/getting-started.yml +++ b/site/data/pages/getting-started.yml @@ -430,8 +430,8 @@ sections: - type: text data: text: > - Chartist generates predefined classes for series by default. Those class names are alpha - numerated and always start with ct-series-a, where the letter a will be iterated + Chartist generates predefined classes for series by default. Those class names are alphabetically + ordered and always start with ct-series-a, where the letter a will be iterated with each series count (a, b, c, d etc.). To address a specific series in styling, you’ll need to create some styles for the corresponding series class name. From ff06309b9f3acedebe027ddf668c7be06b70c208 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 24 May 2019 00:28:56 +0200 Subject: [PATCH 466/593] Added Chartist rescue campaign to readme, website and postinstall --- README.md | 6 ++++++ package.json | 4 +++- rescue-campaign.js | 11 +++++++++++ site/layouts/landing.hbs | 5 +++++ site/styles/_landing.scss | 2 +- site/styles/_rescue.scss | 31 +++++++++++++++++++++++++++++++ site/styles/main.scss | 1 + 7 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 rescue-campaign.js create mode 100644 site/styles/_rescue.scss diff --git a/README.md b/README.md index 348946be..3d4fd629 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ [![Join the chat at https://gitter.im/gionkunz/chartist-js](https://badges.gitter.im/gionkunz/chartist-js.svg)](https://gitter.im/gionkunz/chartist-js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![npm version](http://img.shields.io/npm/v/chartist.svg)](https://npmjs.org/package/chartist) [![build status](http://img.shields.io/travis/gionkunz/chartist-js.svg)](https://travis-ci.org/gionkunz/chartist-js) [![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) +# Chartist needs your help! Please, help me save Chartist! +**Do you like Chartist? Then please help me bring it to the next level and make its maintenance more sustainable in the future.** + +[> HELP TO SAVE CHARTIST <](https://www.kickstarter.com/projects/gionkunz/chartist-10-next-generation-charts-for-the-web) + + ![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") *Checkout the documentation site at http://gionkunz.github.io/chartist-js/* diff --git a/package.json b/package.json index 4126e1e9..d8b3ec45 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "dependencies": {}, "devDependencies": { "assemble-dox": "0.0.2", + "chalk": "^2.4.2", "grunt": "^1.0.1", "grunt-assemble": "^0.4.0", "grunt-concurrent": "^2.3.0", @@ -81,7 +82,8 @@ "dev": "./node_modules/.bin/grunt dev", "build": "./node_modules/.bin/grunt build", "preview": "./node_modules/.bin/grunt preview", - "public": "./node_modules/.bin/grunt public" + "public": "./node_modules/.bin/grunt public", + "postinstall": "node ./rescue-campaign.js" }, "config": { "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> 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", diff --git a/rescue-campaign.js b/rescue-campaign.js new file mode 100644 index 00000000..867f1168 --- /dev/null +++ b/rescue-campaign.js @@ -0,0 +1,11 @@ +const chalk = require('chalk'); + +console.log(chalk.red(' CHARTIST NEEDS YOUR HELP!')); +console.log(chalk.yellow(' _____ _ _ _ _')); +console.log(chalk.yellow(' / ____| | | | (_) | |')); +console.log(chalk.yellow('| | | |__ __ _ _ __| |_ _ ___| |_')); +console.log(chalk.yellow('| | | \'_ \\ / _` | \'__| __| / __| __|')); +console.log(chalk.yellow('| |____| | | | (_| | | | |_| \\__ \\ |_ ')); +console.log(chalk.yellow(' \\_____|_| |_|\\__,_|_| \\__|_|___/\\__|')); +console.log(chalk.yellow('Your support will help to save Chartist.')); +console.log(chalk.yellow('https://tinyurl.com/save-chartist')); diff --git a/site/layouts/landing.hbs b/site/layouts/landing.hbs index fe6bc549..ef1aa582 100644 --- a/site/layouts/landing.hbs +++ b/site/layouts/landing.hbs @@ -1,6 +1,11 @@ --- layout: default --- +
    +
    Chartist needs your help! Please, help me save Chartist!
    +

    Do you like Chartist? Then please help me bring it to the next level and make its maintenance more sustainable in the future.

    + Help to save Chartist +
    Chartist.js diff --git a/site/styles/_landing.scss b/site/styles/_landing.scss index c5fc8317..4cdbd4c7 100644 --- a/site/styles/_landing.scss +++ b/site/styles/_landing.scss @@ -13,7 +13,7 @@ line-height: 0.5; margin-top: 2rem; - @include text-shadow(1px 1px mix(black, $color-yellow, 15%), 2px 2px mix(black, $color-yellow, 15%), 3px 3px mix(black, $color-yellow, 15%)); + text-shadow: 1px 1px mix(black, $color-yellow, 15%), 2px 2px mix(black, $color-yellow, 15%), 3px 3px mix(black, $color-yellow, 15%); @media #{$medium-up} { font-size: rem-calc(nth($modular-scale, 10)); diff --git a/site/styles/_rescue.scss b/site/styles/_rescue.scss new file mode 100644 index 00000000..b8e8db06 --- /dev/null +++ b/site/styles/_rescue.scss @@ -0,0 +1,31 @@ +@import "http://github.com/settings/chartist-docs"; + +.rescue-chartist { + background-color: $color-red; + color: white; + padding: 20px; +} + +.rescue-title { + font-size: 32px; + font-weight: bold; + text-transform: uppercase; + margin-bottom: 10px; +} + +.rescue-message { + font-size: 20px; +} + +.rescue-button { + color: $color-red; + background-color: white; + font-weight: 300 !important; + &:before { + padding-right: 0.5em; + } + + &:hover, + &:focus { color: $color-red; + background-color: $color-white;} +} diff --git a/site/styles/main.scss b/site/styles/main.scss index 9e617c52..f35ae4f0 100644 --- a/site/styles/main.scss +++ b/site/styles/main.scss @@ -17,6 +17,7 @@ @import "http://github.com/api-doc"; @import "http://github.com/live-example"; @import "http://github.com/example-charts"; +@import "http://github.com/rescue"; .button { text-transform: uppercase; From 5cc6c20dff7e16e76acc4225ea455acd5ebda57c Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 24 May 2019 00:30:18 +0200 Subject: [PATCH 467/593] Version bump --- dist/chartist.js | 90 ++++++++++++++++++++++++++-------------- dist/chartist.min.js | 8 ++-- dist/chartist.min.js.map | 2 +- 3 files changed, 64 insertions(+), 36 deletions(-) diff --git a/dist/chartist.js b/dist/chartist.js index 322d8ad7..e3f01dc3 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,8 +14,8 @@ } }(this, function () { -/* Chartist.js 0.11.0 - * Copyright © 2017 Gion Kunz +/* Chartist.js 0.11.1 + * Copyright © 2019 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,12 +26,15 @@ * @module Chartist.Core */ var Chartist = { - version: '0.11.0' + version: '0.11.1' }; -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * This object contains all namespaces used within Chartist. * @@ -1167,14 +1170,14 @@ var Chartist = { return segments; }; -}(window, document, Chartist)); +}(this, Chartist)); ;/** * Chartist path interpolation functions. * * @module Chartist.Interpolation */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; Chartist.Interpolation = {}; @@ -1604,14 +1607,14 @@ var Chartist = { }; }; -}(window, document, Chartist)); +}(this, Chartist)); ;/** * A very basic event module that helps to generate and catch events. * * @module Chartist.Event */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; Chartist.EventEmitter = function () { @@ -1682,14 +1685,14 @@ var Chartist = { }; }; -}(window, document, Chartist)); +}(this, Chartist)); ;/** * This module provides some basic prototype inheritance utilities. * * @module Chartist.Class */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; function listToArray(list) { @@ -1793,16 +1796,18 @@ var Chartist = { cloneDefinitions: cloneDefinitions }; -}(window, document, Chartist)); +}(this, Chartist)); ;/** * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. * * @module Chartist.Base */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. @@ -1986,16 +1991,18 @@ var Chartist = { supportsForeignObject: false }); -}(window, document, Chartist)); +}(this, Chartist)); ;/** * Chartist SVG module for simple SVG DOM abstraction * * @module Chartist.Svg */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; + var document = globalRoot.document; + /** * 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. * @@ -2584,14 +2591,14 @@ var Chartist = { Chartist.Svg.List = Chartist.Class.extend({ constructor: SvgList }); -}(window, document, Chartist)); +}(this, Chartist)); ;/** * Chartist SVG path module for SVG path description creation and modification. * * @module Chartist.Svg.Path */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; /** @@ -2969,11 +2976,14 @@ var Chartist = { Chartist.Svg.Path.elementDescriptions = elementDescriptions; Chartist.Svg.Path.join = join; -}(window, document, Chartist)); +}(this, Chartist)); ;/* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + var axisUnits = { x: { pos: 'x', @@ -3085,7 +3095,7 @@ var Chartist = { Chartist.Axis.units = axisUnits; -}(window, document, Chartist)); +}(this, Chartist)); ;/** * 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. * **Options** @@ -3108,9 +3118,12 @@ var Chartist = { * @module Chartist.AutoScaleAxis */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); @@ -3136,7 +3149,7 @@ var Chartist = { projectValue: projectValue }); -}(window, document, Chartist)); +}(this, Chartist)); ;/** * 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. * **Options** @@ -3157,9 +3170,12 @@ var Chartist = { * @module Chartist.FixedScaleAxis */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + function FixedScaleAxis(axisUnit, data, chartRect, options) { var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); this.divisor = options.divisor || 1; @@ -3192,7 +3208,7 @@ var Chartist = { projectValue: projectValue }); -}(window, document, Chartist)); +}(this, Chartist)); ;/** * 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. * **Options** @@ -3209,9 +3225,12 @@ var Chartist = { * @module Chartist.StepAxis */ /* global Chartist */ -(function (window, document, Chartist) { +(function (globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + function StepAxis(axisUnit, data, chartRect, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, @@ -3232,7 +3251,7 @@ var Chartist = { projectValue: projectValue }); -}(window, document, Chartist)); +}(this, Chartist)); ;/** * 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. * @@ -3241,9 +3260,12 @@ var Chartist = { * @module Chartist.Line */ /* global Chartist */ -(function(window, document, Chartist){ +(function(globalRoot, Chartist){ 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * Default options in line charts. Expand the code view to see a detailed list of options with comments. * @@ -3647,16 +3669,19 @@ var Chartist = { createChart: createChart }); -}(window, document, Chartist)); +}(this, Chartist)); ;/** * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. * * @module Chartist.Bar */ /* global Chartist */ -(function(window, document, Chartist){ +(function(globalRoot, Chartist){ 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * Default options in bar charts. Expand the code view to see a detailed list of options with comments. * @@ -4090,16 +4115,19 @@ var Chartist = { createChart: createChart }); -}(window, document, Chartist)); +}(this, Chartist)); ;/** * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts * * @module Chartist.Pie */ /* global Chartist */ -(function(window, document, Chartist) { +(function(globalRoot, Chartist) { 'use strict'; + var window = globalRoot.window; + var document = globalRoot.document; + /** * Default options in line charts. Expand the code view to see a detailed list of options with comments. * @@ -4481,7 +4509,7 @@ var Chartist = { determineAnchorPosition: determineAnchorPosition }); -}(window, document, Chartist)); +}(this, Chartist)); return Chartist; diff --git a/dist/chartist.min.js b/dist/chartist.min.js index b54d35a0..014fda53 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,10 +1,10 @@ -/* Chartist.js 0.11.0 - * Copyright © 2017 Gion Kunz +/* Chartist.js 0.11.1 + * Copyright © 2019 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 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}); +!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.1"};return function(a,b){"use strict";var c=a.window,d=a.document;b.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"},b.noop=function(a){return a},b.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},b.extend=function(a){var c,d,e;for(a=a||{},c=1;c":">",'"':""","'":"'"},b.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(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,c,b.escapingMap[c])},a))},b.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,b.escapingMap[c],c)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(c){}return a},b.createSvg=function(a,c,d,e){var f;return c=c||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(b.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new b.Svg("svg").attr({width:c,height:d}).addClass(e),f._node.style.width=c,f._node.style.height=d,a.appendChild(f._node),f},b.normalizeData=function(a,c,d){var e,f={raw:a,normalized:{}};return f.normalized.series=b.getDataArray({series:a.series||[]},c,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,b.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),c&&b.reverseData(f.normalized),f},b.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},b.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},b.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},b.isNumeric=function(a){return null!==a&&isFinite(a)},b.isFalseyButZero=function(a){return!a&&0!==a},b.getNumberOrUndefined=function(a){return b.isNumeric(a)?+a:void 0},b.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},b.getMultiValue=function(a,c){return b.isMultiValue(a)?b.getNumberOrUndefined(a[c||"y"]):b.getNumberOrUndefined(a)},b.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},b.getBounds=function(a,c,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:c.high,low:c.low};k.valueRange=k.high-k.low,k.oom=b.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=b.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&b.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(b.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=b.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},b.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)}},b.createChartRect=function(a,c,d){var e=!(!c.axisX&&!c.axisY),f=e?c.axisY.offset:0,g=e?c.axisX.offset:0,h=a.width()||b.quantity(c.width).value||0,i=a.height()||b.quantity(c.height).value||0,j=b.normalizePadding(c.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"===c.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"===c.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},b.createGrid=function(a,c,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",b.extend({type:"grid",axis:d,index:c,group:g,element:k},j))},b.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})},b.createLabel=function(a,c,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]=c,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=d.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",b.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,b.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",b.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},b.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]},b.optionsProvider=function(a,d,e){function f(a){var f=h;if(h=b.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(c[h/2]));return f}}(this,a),function(a,b){"use strict";b.Interpolation={},b.Interpolation.none=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function(c,d){for(var e=new b.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),b.Svg.Path.join(i)}if(c=h[0].pathCoordinates,g=h[0].valueData,c.length<=4)return b.Interpolation.none()(c,g);for(var j,k=(new b.Svg.Path).move(c[0],c[1],!1,g[0]),l=0,m=c.length;m-2*!j>l;l+=2){var n=[{x:+c[l-2],y:+c[l-1]},{x:+c[l],y:+c[l+1]},{x:+c[l+2],y:+c[l+3]},{x:+c[l+4],y:+c[l+5]}];j?l?m-4===l?n[3]={x:+c[0],y:+c[1]}:m-2===l&&(n[2]={x:+c[0],y:+c[1]},n[3]={x:+c[2],y:+c[3]}):n[0]={x:+c[m-2],y:+c[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+c[l],y:+c[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 b.Interpolation.none()([])}},b.Interpolation.monotoneCubic=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function d(c,e){var f=b.splitIntoSegments(c,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))}),b.Svg.Path.join(g)}if(c=f[0].pathCoordinates,e=f[0].valueData,c.length<=4)return b.Interpolation.none()(c,e);var h,i,j=[],k=[],l=c.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 b.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(b){var h=i.elem("path",{d:b.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:c.normalized.series[g],path:b.clone(),series:e,seriesIndex:g,axisX:d,axisY:f,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:f.bounds,chartRect:j,axisX:d,axisY:f,svg:this.svg,options:a})}function d(a,c,d,f){b.Line["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Line=b.Base.extend({constructor:d,createChart:c})}(this,a),function(a,b){"use strict";function c(a){var c,d;a.distributeSeries?(c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),c.normalized.series=c.normalized.series.map(function(a){return[a]})):c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=b.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var f=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!==c.normalized.series.length){var i=b.serialMap(c.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=b.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=b.getHighLow(c.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=b.createChartRect(this.svg,a,e.padding);k=a.distributeSeries&&a.stackBars?c.normalized.labels.slice(0,1):c.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new b.AutoScaleAxis(b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new b.StepAxis(b.Axis.units.y,c.normalized.series,o,{ticks:k}):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new b.StepAxis(b.Axis.units.x,c.normalized.series,o,{ticks:k}):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new b.AutoScaleAxis(b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&b.createGridBackground(f,o,a.classNames.gridBackground,this.eventEmitter),c.raw.series.forEach(function(d,e){var f,h,i=e-(c.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/c.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/c.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":b.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+b.alphaNumerate(e)].join(" ")),c.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,c.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,c.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,c.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,c.normalized.series[e])},l instanceof b.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=b.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(b.isNumeric).join(","),"ct:meta":b.serialize(w)}),this.eventEmitter.emit("draw",b.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 d(a,c,d,f){b.Bar["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Bar=b.Base.extend({constructor:d,createChart:c})}(this,a),function(a,b){"use strict";function c(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 d(a){var d,e,g,h,i,j=b.normalizeData(this.data),k=[],l=a.startAngle;this.svg=b.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=b.createChartRect(this.svg,a,f.padding),g=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=b.quantity(a.donutWidth);"%"===m.unit&&(m.value*=g/100),g-=a.donut&&!a.donutSolid?m.value/2:0,h="outside"===a.labelPosition||a.donut&&!a.donutSolid?g:"center"===a.labelPosition?0:a.donutSolid?g-m.value/2:g/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&&(d=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,f){if(0!==j.normalized.series[f]||!a.ignoreEmptyValues){k[f].attr({"ct:series-name":e.name}),k[f].addClass([a.classNames.series,e.className||a.classNames.series+"-"+b.alphaNumerate(f)].join(" "));var p=i>0?l+j.normalized.series[f]/i*360:0,q=Math.max(0,l-(0===f||o?0:.2));p-q>=359.99&&(p=q+359.99);var r,s,t,u=b.polarToCartesian(n.x,n.y,g,q),v=b.polarToCartesian(n.x,n.y,g,p),w=new b.Svg.Path(!a.donut||a.donutSolid).move(v.x,v.y).arc(g,g,0,p-l>180,0,u.x,u.y);a.donut?a.donutSolid&&(t=g-m.value,r=b.polarToCartesian(n.x,n.y,t,l-(0===f||o?0:.2)),s=b.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[f].elem("path",{d:w.stringify()},x);if(y.attr({"ct:value":j.normalized.series[f],"ct:meta":b.serialize(e.meta)}),a.donut&&!a.donutSolid&&(y._node.style.strokeWidth=m.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[f],totalDataSum:i,index:f,meta:e.meta,series:e,group:k[f],element:y,path:w.clone(),center:n,radius:g,startAngle:l,endAngle:p}),a.showLabel){var z;z=1===j.raw.series.length?{x:n.x,y:n.y}:b.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var A;A=j.normalized.labels&&!b.isFalseyButZero(j.normalized.labels[f])?j.normalized.labels[f]:j.normalized.series[f];var B=a.labelInterpolationFnc(A,f);if(B||0===B){var C=d.elem("text",{dx:z.x,dy:z.y,"text-anchor":c(n,z,a.labelDirection)},a.classNames.label).text(""+B);this.eventEmitter.emit("draw",{type:"label",index:f,group:d,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 e(a,c,d,e){b.Pie["super"].constructor.call(this,a,c,f,b.extend({},f,d),e)}var f=(a.window,a.document,{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:b.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1});b.Pie=b.Base.extend({constructor:e,createChart:d,determineAnchorPosition:c})}(this,a),a}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index bdcce040..46c5902e 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"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 +{"version":3,"sources":["chartist.js"],"names":["root","factory","define","amd","module","exports","this","Chartist","version","globalRoot","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.1\n * Copyright © 2019 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.1'\n};\n\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, Chartist));\n;/**\n * Chartist path interpolation functions.\n *\n * @module Chartist.Interpolation\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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 (globalRoot, 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}(this, Chartist));\n;/**\n * This module provides some basic prototype inheritance utilities.\n *\n * @module Chartist.Class\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\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}(this, Chartist));\n;/**\n * Chartist SVG module for simple SVG DOM abstraction\n *\n * @module Chartist.Svg\n */\n/* global Chartist */\n(function(globalRoot, Chartist) {\n 'use strict';\n\n var document = globalRoot.document;\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}(this, 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(globalRoot, 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}(this, Chartist));\n;/* global Chartist */\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, Chartist));\n\nreturn Chartist;\n\n}));\n"]} \ No newline at end of file From 80b4f459ac464df0e3f406d21e90ac0e4fb64f60 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 24 May 2019 00:31:13 +0200 Subject: [PATCH 468/593] Fixed package.json version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d8b3ec45..dfa98da4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.11.0", + "version": "0.11.1", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { From beb5b4a811ab04e8a1e6d1989425810274e03d56 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 24 May 2019 01:15:32 +0200 Subject: [PATCH 469/593] Version bump --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index dfa98da4..59010b46 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.11.1", + "version": "0.11.2", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { @@ -23,7 +23,8 @@ "LICENSE-WTFPL", "LICENSE-MIT", "package.json", - "README.md" + "README.md", + "rescue-campaign.js" ], "style": "dist/chartist.min.css", "main": "dist/chartist.js", From b7810e430c55045f11b953ec12491a5a2d01f647 Mon Sep 17 00:00:00 2001 From: Larry Botha Date: Wed, 19 Jun 2019 18:11:37 -0500 Subject: [PATCH 470/593] fix(this / global): use this or global to fix 'this' breaking tests / builds in node environments --- dist/chartist.js | 32 ++++++++++++++-------------- dist/chartist.min.js | 6 +++--- dist/chartist.min.js.map | 2 +- src/scripts/axes/auto-scale-axis.js | 2 +- src/scripts/axes/axis.js | 2 +- src/scripts/axes/fixed-scale-axis.js | 2 +- src/scripts/axes/step-axis.js | 2 +- src/scripts/base.js | 2 +- src/scripts/charts/bar.js | 2 +- src/scripts/charts/line.js | 2 +- src/scripts/charts/pie.js | 2 +- src/scripts/class.js | 2 +- src/scripts/core.js | 2 +- src/scripts/event.js | 2 +- src/scripts/interpolation.js | 2 +- src/scripts/svg-path.js | 2 +- src/scripts/svg.js | 2 +- 17 files changed, 34 insertions(+), 34 deletions(-) diff --git a/dist/chartist.js b/dist/chartist.js index e3f01dc3..44494dbd 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.11.1 +/* Chartist.js 0.11.2 * Copyright © 2019 Gion Kunz * Free to use under either the WTFPL license or the MIT license. * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL @@ -26,7 +26,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.11.1' + version: '0.11.2' }; (function (globalRoot, Chartist) { @@ -1170,7 +1170,7 @@ var Chartist = { return segments; }; -}(this, Chartist)); +}(this || global, Chartist)); ;/** * Chartist path interpolation functions. * @@ -1607,7 +1607,7 @@ var Chartist = { }; }; -}(this, Chartist)); +}(this || global, Chartist)); ;/** * A very basic event module that helps to generate and catch events. * @@ -1685,7 +1685,7 @@ var Chartist = { }; }; -}(this, Chartist)); +}(this || global, Chartist)); ;/** * This module provides some basic prototype inheritance utilities. * @@ -1796,7 +1796,7 @@ var Chartist = { cloneDefinitions: cloneDefinitions }; -}(this, Chartist)); +}(this || global, Chartist)); ;/** * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. * @@ -1991,7 +1991,7 @@ var Chartist = { supportsForeignObject: false }); -}(this, Chartist)); +}(this || global, Chartist)); ;/** * Chartist SVG module for simple SVG DOM abstraction * @@ -2591,7 +2591,7 @@ var Chartist = { Chartist.Svg.List = Chartist.Class.extend({ constructor: SvgList }); -}(this, Chartist)); +}(this || global, Chartist)); ;/** * Chartist SVG path module for SVG path description creation and modification. * @@ -2976,7 +2976,7 @@ var Chartist = { Chartist.Svg.Path.elementDescriptions = elementDescriptions; Chartist.Svg.Path.join = join; -}(this, Chartist)); +}(this || global, Chartist)); ;/* global Chartist */ (function (globalRoot, Chartist) { 'use strict'; @@ -3095,7 +3095,7 @@ var Chartist = { Chartist.Axis.units = axisUnits; -}(this, Chartist)); +}(this || global, Chartist)); ;/** * 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. * **Options** @@ -3149,7 +3149,7 @@ var Chartist = { projectValue: projectValue }); -}(this, Chartist)); +}(this || global, Chartist)); ;/** * 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. * **Options** @@ -3208,7 +3208,7 @@ var Chartist = { projectValue: projectValue }); -}(this, Chartist)); +}(this || global, Chartist)); ;/** * 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. * **Options** @@ -3251,7 +3251,7 @@ var Chartist = { projectValue: projectValue }); -}(this, Chartist)); +}(this || global, Chartist)); ;/** * 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. * @@ -3669,7 +3669,7 @@ var Chartist = { createChart: createChart }); -}(this, Chartist)); +}(this || global, Chartist)); ;/** * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. * @@ -4115,7 +4115,7 @@ var Chartist = { createChart: createChart }); -}(this, Chartist)); +}(this || global, Chartist)); ;/** * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts * @@ -4509,7 +4509,7 @@ var Chartist = { determineAnchorPosition: determineAnchorPosition }); -}(this, Chartist)); +}(this || global, Chartist)); return Chartist; diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 014fda53..80042563 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,10 +1,10 @@ -/* Chartist.js 0.11.1 +/* Chartist.js 0.11.2 * Copyright © 2019 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 module&&module.exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.11.1"};return function(a,b){"use strict";var c=a.window,d=a.document;b.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"},b.noop=function(a){return a},b.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},b.extend=function(a){var c,d,e;for(a=a||{},c=1;c":">",'"':""","'":"'"},b.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(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,c,b.escapingMap[c])},a))},b.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,b.escapingMap[c],c)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(c){}return a},b.createSvg=function(a,c,d,e){var f;return c=c||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(b.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new b.Svg("svg").attr({width:c,height:d}).addClass(e),f._node.style.width=c,f._node.style.height=d,a.appendChild(f._node),f},b.normalizeData=function(a,c,d){var e,f={raw:a,normalized:{}};return f.normalized.series=b.getDataArray({series:a.series||[]},c,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,b.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),c&&b.reverseData(f.normalized),f},b.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},b.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},b.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},b.isNumeric=function(a){return null!==a&&isFinite(a)},b.isFalseyButZero=function(a){return!a&&0!==a},b.getNumberOrUndefined=function(a){return b.isNumeric(a)?+a:void 0},b.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},b.getMultiValue=function(a,c){return b.isMultiValue(a)?b.getNumberOrUndefined(a[c||"y"]):b.getNumberOrUndefined(a)},b.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},b.getBounds=function(a,c,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:c.high,low:c.low};k.valueRange=k.high-k.low,k.oom=b.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=b.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&b.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(b.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=b.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},b.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)}},b.createChartRect=function(a,c,d){var e=!(!c.axisX&&!c.axisY),f=e?c.axisY.offset:0,g=e?c.axisX.offset:0,h=a.width()||b.quantity(c.width).value||0,i=a.height()||b.quantity(c.height).value||0,j=b.normalizePadding(c.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"===c.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"===c.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},b.createGrid=function(a,c,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",b.extend({type:"grid",axis:d,index:c,group:g,element:k},j))},b.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})},b.createLabel=function(a,c,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]=c,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=d.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",b.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,b.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",b.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},b.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]},b.optionsProvider=function(a,d,e){function f(a){var f=h;if(h=b.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(c[h/2]));return f}}(this,a),function(a,b){"use strict";b.Interpolation={},b.Interpolation.none=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function(c,d){for(var e=new b.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),b.Svg.Path.join(i)}if(c=h[0].pathCoordinates,g=h[0].valueData,c.length<=4)return b.Interpolation.none()(c,g);for(var j,k=(new b.Svg.Path).move(c[0],c[1],!1,g[0]),l=0,m=c.length;m-2*!j>l;l+=2){var n=[{x:+c[l-2],y:+c[l-1]},{x:+c[l],y:+c[l+1]},{x:+c[l+2],y:+c[l+3]},{x:+c[l+4],y:+c[l+5]}];j?l?m-4===l?n[3]={x:+c[0],y:+c[1]}:m-2===l&&(n[2]={x:+c[0],y:+c[1]},n[3]={x:+c[2],y:+c[3]}):n[0]={x:+c[m-2],y:+c[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+c[l],y:+c[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 b.Interpolation.none()([])}},b.Interpolation.monotoneCubic=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function d(c,e){var f=b.splitIntoSegments(c,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))}),b.Svg.Path.join(g)}if(c=f[0].pathCoordinates,e=f[0].valueData,c.length<=4)return b.Interpolation.none()(c,e);var h,i,j=[],k=[],l=c.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 b.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(b){var h=i.elem("path",{d:b.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:c.normalized.series[g],path:b.clone(),series:e,seriesIndex:g,axisX:d,axisY:f,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:f.bounds,chartRect:j,axisX:d,axisY:f,svg:this.svg,options:a})}function d(a,c,d,f){b.Line["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Line=b.Base.extend({constructor:d,createChart:c})}(this,a),function(a,b){"use strict";function c(a){var c,d;a.distributeSeries?(c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),c.normalized.series=c.normalized.series.map(function(a){return[a]})):c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=b.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var f=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!==c.normalized.series.length){var i=b.serialMap(c.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=b.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=b.getHighLow(c.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=b.createChartRect(this.svg,a,e.padding);k=a.distributeSeries&&a.stackBars?c.normalized.labels.slice(0,1):c.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new b.AutoScaleAxis(b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new b.StepAxis(b.Axis.units.y,c.normalized.series,o,{ticks:k}):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new b.StepAxis(b.Axis.units.x,c.normalized.series,o,{ticks:k}):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new b.AutoScaleAxis(b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&b.createGridBackground(f,o,a.classNames.gridBackground,this.eventEmitter),c.raw.series.forEach(function(d,e){var f,h,i=e-(c.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/c.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/c.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":b.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+b.alphaNumerate(e)].join(" ")),c.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,c.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,c.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,c.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,c.normalized.series[e])},l instanceof b.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=b.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(b.isNumeric).join(","),"ct:meta":b.serialize(w)}),this.eventEmitter.emit("draw",b.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 d(a,c,d,f){b.Bar["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Bar=b.Base.extend({constructor:d,createChart:c})}(this,a),function(a,b){"use strict";function c(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 d(a){var d,e,g,h,i,j=b.normalizeData(this.data),k=[],l=a.startAngle;this.svg=b.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=b.createChartRect(this.svg,a,f.padding),g=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=b.quantity(a.donutWidth);"%"===m.unit&&(m.value*=g/100),g-=a.donut&&!a.donutSolid?m.value/2:0,h="outside"===a.labelPosition||a.donut&&!a.donutSolid?g:"center"===a.labelPosition?0:a.donutSolid?g-m.value/2:g/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&&(d=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,f){if(0!==j.normalized.series[f]||!a.ignoreEmptyValues){k[f].attr({"ct:series-name":e.name}),k[f].addClass([a.classNames.series,e.className||a.classNames.series+"-"+b.alphaNumerate(f)].join(" "));var p=i>0?l+j.normalized.series[f]/i*360:0,q=Math.max(0,l-(0===f||o?0:.2));p-q>=359.99&&(p=q+359.99);var r,s,t,u=b.polarToCartesian(n.x,n.y,g,q),v=b.polarToCartesian(n.x,n.y,g,p),w=new b.Svg.Path(!a.donut||a.donutSolid).move(v.x,v.y).arc(g,g,0,p-l>180,0,u.x,u.y);a.donut?a.donutSolid&&(t=g-m.value,r=b.polarToCartesian(n.x,n.y,t,l-(0===f||o?0:.2)),s=b.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[f].elem("path",{d:w.stringify()},x);if(y.attr({"ct:value":j.normalized.series[f],"ct:meta":b.serialize(e.meta)}),a.donut&&!a.donutSolid&&(y._node.style.strokeWidth=m.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[f],totalDataSum:i,index:f,meta:e.meta,series:e,group:k[f],element:y,path:w.clone(),center:n,radius:g,startAngle:l,endAngle:p}),a.showLabel){var z;z=1===j.raw.series.length?{x:n.x,y:n.y}:b.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var A;A=j.normalized.labels&&!b.isFalseyButZero(j.normalized.labels[f])?j.normalized.labels[f]:j.normalized.series[f];var B=a.labelInterpolationFnc(A,f);if(B||0===B){var C=d.elem("text",{dx:z.x,dy:z.y,"text-anchor":c(n,z,a.labelDirection)},a.classNames.label).text(""+B);this.eventEmitter.emit("draw",{type:"label",index:f,group:d,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 e(a,c,d,e){b.Pie["super"].constructor.call(this,a,c,f,b.extend({},f,d),e)}var f=(a.window,a.document,{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:b.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1});b.Pie=b.Base.extend({constructor:e,createChart:d,determineAnchorPosition:c})}(this,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.2"};return function(a,b){"use strict";var c=a.window,d=a.document;b.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"},b.noop=function(a){return a},b.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},b.extend=function(a){var c,d,e;for(a=a||{},c=1;c":">",'"':""","'":"'"},b.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(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,c,b.escapingMap[c])},a))},b.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,b.escapingMap[c],c)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(c){}return a},b.createSvg=function(a,c,d,e){var f;return c=c||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(b.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new b.Svg("svg").attr({width:c,height:d}).addClass(e),f._node.style.width=c,f._node.style.height=d,a.appendChild(f._node),f},b.normalizeData=function(a,c,d){var e,f={raw:a,normalized:{}};return f.normalized.series=b.getDataArray({series:a.series||[]},c,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,b.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),c&&b.reverseData(f.normalized),f},b.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},b.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},b.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},b.isNumeric=function(a){return null!==a&&isFinite(a)},b.isFalseyButZero=function(a){return!a&&0!==a},b.getNumberOrUndefined=function(a){return b.isNumeric(a)?+a:void 0},b.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},b.getMultiValue=function(a,c){return b.isMultiValue(a)?b.getNumberOrUndefined(a[c||"y"]):b.getNumberOrUndefined(a)},b.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},b.getBounds=function(a,c,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:c.high,low:c.low};k.valueRange=k.high-k.low,k.oom=b.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=b.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&b.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(b.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=b.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},b.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)}},b.createChartRect=function(a,c,d){var e=!(!c.axisX&&!c.axisY),f=e?c.axisY.offset:0,g=e?c.axisX.offset:0,h=a.width()||b.quantity(c.width).value||0,i=a.height()||b.quantity(c.height).value||0,j=b.normalizePadding(c.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"===c.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"===c.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},b.createGrid=function(a,c,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",b.extend({type:"grid",axis:d,index:c,group:g,element:k},j))},b.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})},b.createLabel=function(a,c,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]=c,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=d.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",b.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,b.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",b.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},b.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]},b.optionsProvider=function(a,d,e){function f(a){var f=h;if(h=b.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(c[h/2]));return f}}(this||global,a),function(a,b){"use strict";b.Interpolation={},b.Interpolation.none=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function(c,d){for(var e=new b.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),b.Svg.Path.join(i)}if(c=h[0].pathCoordinates,g=h[0].valueData,c.length<=4)return b.Interpolation.none()(c,g);for(var j,k=(new b.Svg.Path).move(c[0],c[1],!1,g[0]),l=0,m=c.length;m-2*!j>l;l+=2){var n=[{x:+c[l-2],y:+c[l-1]},{x:+c[l],y:+c[l+1]},{x:+c[l+2],y:+c[l+3]},{x:+c[l+4],y:+c[l+5]}];j?l?m-4===l?n[3]={x:+c[0],y:+c[1]}:m-2===l&&(n[2]={x:+c[0],y:+c[1]},n[3]={x:+c[2],y:+c[3]}):n[0]={x:+c[m-2],y:+c[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+c[l],y:+c[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 b.Interpolation.none()([])}},b.Interpolation.monotoneCubic=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function d(c,e){var f=b.splitIntoSegments(c,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))}),b.Svg.Path.join(g)}if(c=f[0].pathCoordinates,e=f[0].valueData,c.length<=4)return b.Interpolation.none()(c,e);var h,i,j=[],k=[],l=c.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 b.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(b){var h=i.elem("path",{d:b.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:c.normalized.series[g],path:b.clone(),series:e,seriesIndex:g,axisX:d,axisY:f,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:f.bounds,chartRect:j,axisX:d,axisY:f,svg:this.svg,options:a})}function d(a,c,d,f){b.Line["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Line=b.Base.extend({constructor:d,createChart:c})}(this||global,a),function(a,b){"use strict";function c(a){var c,d;a.distributeSeries?(c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),c.normalized.series=c.normalized.series.map(function(a){return[a]})):c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=b.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var f=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!==c.normalized.series.length){var i=b.serialMap(c.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=b.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=b.getHighLow(c.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=b.createChartRect(this.svg,a,e.padding);k=a.distributeSeries&&a.stackBars?c.normalized.labels.slice(0,1):c.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new b.AutoScaleAxis(b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new b.StepAxis(b.Axis.units.y,c.normalized.series,o,{ticks:k}):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new b.StepAxis(b.Axis.units.x,c.normalized.series,o,{ticks:k}):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new b.AutoScaleAxis(b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&b.createGridBackground(f,o,a.classNames.gridBackground,this.eventEmitter),c.raw.series.forEach(function(d,e){var f,h,i=e-(c.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/c.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/c.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":b.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+b.alphaNumerate(e)].join(" ")),c.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,c.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,c.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,c.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,c.normalized.series[e])},l instanceof b.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=b.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(b.isNumeric).join(","),"ct:meta":b.serialize(w)}),this.eventEmitter.emit("draw",b.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 d(a,c,d,f){b.Bar["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Bar=b.Base.extend({constructor:d,createChart:c})}(this||global,a),function(a,b){"use strict";function c(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 d(a){var d,e,g,h,i,j=b.normalizeData(this.data),k=[],l=a.startAngle;this.svg=b.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=b.createChartRect(this.svg,a,f.padding),g=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=b.quantity(a.donutWidth);"%"===m.unit&&(m.value*=g/100),g-=a.donut&&!a.donutSolid?m.value/2:0,h="outside"===a.labelPosition||a.donut&&!a.donutSolid?g:"center"===a.labelPosition?0:a.donutSolid?g-m.value/2:g/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&&(d=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,f){if(0!==j.normalized.series[f]||!a.ignoreEmptyValues){k[f].attr({"ct:series-name":e.name}),k[f].addClass([a.classNames.series,e.className||a.classNames.series+"-"+b.alphaNumerate(f)].join(" "));var p=i>0?l+j.normalized.series[f]/i*360:0,q=Math.max(0,l-(0===f||o?0:.2));p-q>=359.99&&(p=q+359.99);var r,s,t,u=b.polarToCartesian(n.x,n.y,g,q),v=b.polarToCartesian(n.x,n.y,g,p),w=new b.Svg.Path(!a.donut||a.donutSolid).move(v.x,v.y).arc(g,g,0,p-l>180,0,u.x,u.y);a.donut?a.donutSolid&&(t=g-m.value,r=b.polarToCartesian(n.x,n.y,t,l-(0===f||o?0:.2)),s=b.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[f].elem("path",{d:w.stringify()},x);if(y.attr({"ct:value":j.normalized.series[f],"ct:meta":b.serialize(e.meta)}),a.donut&&!a.donutSolid&&(y._node.style.strokeWidth=m.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[f],totalDataSum:i,index:f,meta:e.meta,series:e,group:k[f],element:y,path:w.clone(),center:n,radius:g,startAngle:l,endAngle:p}),a.showLabel){var z;z=1===j.raw.series.length?{x:n.x,y:n.y}:b.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var A;A=j.normalized.labels&&!b.isFalseyButZero(j.normalized.labels[f])?j.normalized.labels[f]:j.normalized.series[f];var B=a.labelInterpolationFnc(A,f);if(B||0===B){var C=d.elem("text",{dx:z.x,dy:z.y,"text-anchor":c(n,z,a.labelDirection)},a.classNames.label).text(""+B);this.eventEmitter.emit("draw",{type:"label",index:f,group:d,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 e(a,c,d,e){b.Pie["super"].constructor.call(this,a,c,f,b.extend({},f,d),e)}var f=(a.window,a.document,{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:b.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1});b.Pie=b.Base.extend({constructor:e,createChart:d,determineAnchorPosition:c})}(this||global,a),a}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index 46c5902e..5a1a9908 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["chartist.js"],"names":["root","factory","define","amd","module","exports","this","Chartist","version","globalRoot","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.1\n * Copyright © 2019 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.1'\n};\n\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, Chartist));\n;/**\n * Chartist path interpolation functions.\n *\n * @module Chartist.Interpolation\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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 (globalRoot, 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}(this, Chartist));\n;/**\n * This module provides some basic prototype inheritance utilities.\n *\n * @module Chartist.Class\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\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}(this, Chartist));\n;/**\n * Chartist SVG module for simple SVG DOM abstraction\n *\n * @module Chartist.Svg\n */\n/* global Chartist */\n(function(globalRoot, Chartist) {\n 'use strict';\n\n var document = globalRoot.document;\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}(this, 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(globalRoot, 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}(this, Chartist));\n;/* global Chartist */\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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","globalRoot","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","global","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.2\n * Copyright © 2019 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.2'\n};\n\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, Chartist));\n;/**\n * Chartist path interpolation functions.\n *\n * @module Chartist.Interpolation\n */\n/* global Chartist */\n(function(globalRoot, 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}(this || global, 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 (globalRoot, 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}(this || global, Chartist));\n;/**\n * This module provides some basic prototype inheritance utilities.\n *\n * @module Chartist.Class\n */\n/* global Chartist */\n(function(globalRoot, 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}(this || global, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\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}(this || global, Chartist));\n;/**\n * Chartist SVG module for simple SVG DOM abstraction\n *\n * @module Chartist.Svg\n */\n/* global Chartist */\n(function(globalRoot, Chartist) {\n 'use strict';\n\n var document = globalRoot.document;\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}(this || global, 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(globalRoot, 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}(this || global, Chartist));\n;/* global Chartist */\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this || global, Chartist));\n\nreturn Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/src/scripts/axes/auto-scale-axis.js b/src/scripts/axes/auto-scale-axis.js index 442db76c..977f5a7d 100644 --- a/src/scripts/axes/auto-scale-axis.js +++ b/src/scripts/axes/auto-scale-axis.js @@ -51,4 +51,4 @@ projectValue: projectValue }); -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/axes/axis.js b/src/scripts/axes/axis.js index 21c576fd..5f0cb8c9 100644 --- a/src/scripts/axes/axis.js +++ b/src/scripts/axes/axis.js @@ -116,4 +116,4 @@ Chartist.Axis.units = axisUnits; -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/axes/fixed-scale-axis.js b/src/scripts/axes/fixed-scale-axis.js index 1af1245c..3b908850 100644 --- a/src/scripts/axes/fixed-scale-axis.js +++ b/src/scripts/axes/fixed-scale-axis.js @@ -56,4 +56,4 @@ projectValue: projectValue }); -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/axes/step-axis.js b/src/scripts/axes/step-axis.js index f0f1ddfe..394ba1a6 100644 --- a/src/scripts/axes/step-axis.js +++ b/src/scripts/axes/step-axis.js @@ -40,4 +40,4 @@ projectValue: projectValue }); -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/base.js b/src/scripts/base.js index 88d68304..98ff6bc9 100644 --- a/src/scripts/base.js +++ b/src/scripts/base.js @@ -192,4 +192,4 @@ supportsForeignObject: false }); -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/charts/bar.js b/src/scripts/charts/bar.js index eef434fa..39a4137b 100644 --- a/src/scripts/charts/bar.js +++ b/src/scripts/charts/bar.js @@ -443,4 +443,4 @@ createChart: createChart }); -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/charts/line.js b/src/scripts/charts/line.js index a71c0d37..7ca58eeb 100644 --- a/src/scripts/charts/line.js +++ b/src/scripts/charts/line.js @@ -415,4 +415,4 @@ createChart: createChart }); -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/charts/pie.js b/src/scripts/charts/pie.js index 22125b68..41b72edd 100644 --- a/src/scripts/charts/pie.js +++ b/src/scripts/charts/pie.js @@ -391,4 +391,4 @@ determineAnchorPosition: determineAnchorPosition }); -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/class.js b/src/scripts/class.js index b770fb95..2c6d4c7c 100644 --- a/src/scripts/class.js +++ b/src/scripts/class.js @@ -108,4 +108,4 @@ cloneDefinitions: cloneDefinitions }; -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/core.js b/src/scripts/core.js index 94741ba6..3ec20ffb 100644 --- a/src/scripts/core.js +++ b/src/scripts/core.js @@ -1148,4 +1148,4 @@ var Chartist = { return segments; }; -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/event.js b/src/scripts/event.js index d6fd8669..3333e533 100644 --- a/src/scripts/event.js +++ b/src/scripts/event.js @@ -75,4 +75,4 @@ }; }; -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/interpolation.js b/src/scripts/interpolation.js index a60d1720..0cd3260a 100644 --- a/src/scripts/interpolation.js +++ b/src/scripts/interpolation.js @@ -434,4 +434,4 @@ }; }; -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/svg-path.js b/src/scripts/svg-path.js index f6724ff3..c55a9762 100644 --- a/src/scripts/svg-path.js +++ b/src/scripts/svg-path.js @@ -382,4 +382,4 @@ Chartist.Svg.Path.elementDescriptions = elementDescriptions; Chartist.Svg.Path.join = join; -}(this, Chartist)); +}(this || global, Chartist)); diff --git a/src/scripts/svg.js b/src/scripts/svg.js index 866ad749..c1b7875c 100644 --- a/src/scripts/svg.js +++ b/src/scripts/svg.js @@ -597,4 +597,4 @@ Chartist.Svg.List = Chartist.Class.extend({ constructor: SvgList }); -}(this, Chartist)); +}(this || global, Chartist)); From 0271b06be5df333b2ed5aa1a9f38ba004ac84bc9 Mon Sep 17 00:00:00 2001 From: Gion Kunz Date: Fri, 5 Jul 2019 23:57:51 +0200 Subject: [PATCH 471/593] Removed rescue campaign and added affiliate to creative tim --- README.md | 6 ------ dist/chartist.js | 4 ++-- dist/chartist.min.js | 4 ++-- dist/chartist.min.js.map | 2 +- package.json | 6 ++---- rescue-campaign.js | 11 ---------- site/data/pages/index.yml | 16 +++++++++++++++ site/layouts/landing.hbs | 5 ----- site/partials/affiliate-project.hbs | 5 +++++ site/styles/_affiliate-project.scss | 31 +++++++++++++++++++++++++++++ site/styles/_rescue.scss | 31 ----------------------------- site/styles/main.scss | 2 +- site/templates/index.hbs | 8 ++++++++ 13 files changed, 68 insertions(+), 63 deletions(-) delete mode 100644 rescue-campaign.js create mode 100644 site/partials/affiliate-project.hbs create mode 100644 site/styles/_affiliate-project.scss delete mode 100644 site/styles/_rescue.scss diff --git a/README.md b/README.md index 3d4fd629..348946be 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,6 @@ [![Join the chat at https://gitter.im/gionkunz/chartist-js](https://badges.gitter.im/gionkunz/chartist-js.svg)](https://gitter.im/gionkunz/chartist-js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![npm version](http://img.shields.io/npm/v/chartist.svg)](https://npmjs.org/package/chartist) [![build status](http://img.shields.io/travis/gionkunz/chartist-js.svg)](https://travis-ci.org/gionkunz/chartist-js) [![Inline docs](http://inch-ci.org/github/gionkunz/chartist-js.svg?branch=develop)](http://inch-ci.org/github/gionkunz/chartist-js) -# Chartist needs your help! Please, help me save Chartist! -**Do you like Chartist? Then please help me bring it to the next level and make its maintenance more sustainable in the future.** - -[> HELP TO SAVE CHARTIST <](https://www.kickstarter.com/projects/gionkunz/chartist-10-next-generation-charts-for-the-web) - - ![The Chartist Guy](https://raw.github.com/gionkunz/chartist-js/develop/site/images/chartist-guy.gif "The Chartist Guy") *Checkout the documentation site at http://gionkunz.github.io/chartist-js/* diff --git a/dist/chartist.js b/dist/chartist.js index e3f01dc3..26d20b20 100644 --- a/dist/chartist.js +++ b/dist/chartist.js @@ -14,7 +14,7 @@ } }(this, function () { -/* Chartist.js 0.11.1 +/* Chartist.js 0.11.3 * Copyright © 2019 Gion Kunz * Free to use under either the WTFPL license or the MIT license. * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL @@ -26,7 +26,7 @@ * @module Chartist.Core */ var Chartist = { - version: '0.11.1' + version: '0.11.3' }; (function (globalRoot, Chartist) { diff --git a/dist/chartist.min.js b/dist/chartist.min.js index 014fda53..634fb0e9 100644 --- a/dist/chartist.min.js +++ b/dist/chartist.min.js @@ -1,10 +1,10 @@ -/* Chartist.js 0.11.1 +/* Chartist.js 0.11.3 * Copyright © 2019 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 module&&module.exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.11.1"};return function(a,b){"use strict";var c=a.window,d=a.document;b.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"},b.noop=function(a){return a},b.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},b.extend=function(a){var c,d,e;for(a=a||{},c=1;c":">",'"':""","'":"'"},b.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(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,c,b.escapingMap[c])},a))},b.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,b.escapingMap[c],c)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(c){}return a},b.createSvg=function(a,c,d,e){var f;return c=c||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(b.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new b.Svg("svg").attr({width:c,height:d}).addClass(e),f._node.style.width=c,f._node.style.height=d,a.appendChild(f._node),f},b.normalizeData=function(a,c,d){var e,f={raw:a,normalized:{}};return f.normalized.series=b.getDataArray({series:a.series||[]},c,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,b.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),c&&b.reverseData(f.normalized),f},b.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},b.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},b.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},b.isNumeric=function(a){return null!==a&&isFinite(a)},b.isFalseyButZero=function(a){return!a&&0!==a},b.getNumberOrUndefined=function(a){return b.isNumeric(a)?+a:void 0},b.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},b.getMultiValue=function(a,c){return b.isMultiValue(a)?b.getNumberOrUndefined(a[c||"y"]):b.getNumberOrUndefined(a)},b.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},b.getBounds=function(a,c,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:c.high,low:c.low};k.valueRange=k.high-k.low,k.oom=b.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=b.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&b.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(b.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=b.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},b.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)}},b.createChartRect=function(a,c,d){var e=!(!c.axisX&&!c.axisY),f=e?c.axisY.offset:0,g=e?c.axisX.offset:0,h=a.width()||b.quantity(c.width).value||0,i=a.height()||b.quantity(c.height).value||0,j=b.normalizePadding(c.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"===c.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"===c.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},b.createGrid=function(a,c,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",b.extend({type:"grid",axis:d,index:c,group:g,element:k},j))},b.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})},b.createLabel=function(a,c,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]=c,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=d.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",b.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,b.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",b.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},b.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]},b.optionsProvider=function(a,d,e){function f(a){var f=h;if(h=b.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(c[h/2]));return f}}(this,a),function(a,b){"use strict";b.Interpolation={},b.Interpolation.none=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function(c,d){for(var e=new b.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),b.Svg.Path.join(i)}if(c=h[0].pathCoordinates,g=h[0].valueData,c.length<=4)return b.Interpolation.none()(c,g);for(var j,k=(new b.Svg.Path).move(c[0],c[1],!1,g[0]),l=0,m=c.length;m-2*!j>l;l+=2){var n=[{x:+c[l-2],y:+c[l-1]},{x:+c[l],y:+c[l+1]},{x:+c[l+2],y:+c[l+3]},{x:+c[l+4],y:+c[l+5]}];j?l?m-4===l?n[3]={x:+c[0],y:+c[1]}:m-2===l&&(n[2]={x:+c[0],y:+c[1]},n[3]={x:+c[2],y:+c[3]}):n[0]={x:+c[m-2],y:+c[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+c[l],y:+c[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 b.Interpolation.none()([])}},b.Interpolation.monotoneCubic=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function d(c,e){var f=b.splitIntoSegments(c,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))}),b.Svg.Path.join(g)}if(c=f[0].pathCoordinates,e=f[0].valueData,c.length<=4)return b.Interpolation.none()(c,e);var h,i,j=[],k=[],l=c.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 b.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(b){var h=i.elem("path",{d:b.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:c.normalized.series[g],path:b.clone(),series:e,seriesIndex:g,axisX:d,axisY:f,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:f.bounds,chartRect:j,axisX:d,axisY:f,svg:this.svg,options:a})}function d(a,c,d,f){b.Line["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Line=b.Base.extend({constructor:d,createChart:c})}(this,a),function(a,b){"use strict";function c(a){var c,d;a.distributeSeries?(c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),c.normalized.series=c.normalized.series.map(function(a){return[a]})):c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=b.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var f=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!==c.normalized.series.length){var i=b.serialMap(c.normalized.series,function(){ +!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.3"};return function(a,b){"use strict";var c=a.window,d=a.document;b.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"},b.noop=function(a){return a},b.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},b.extend=function(a){var c,d,e;for(a=a||{},c=1;c":">",'"':""","'":"'"},b.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(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,c,b.escapingMap[c])},a))},b.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,b.escapingMap[c],c)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(c){}return a},b.createSvg=function(a,c,d,e){var f;return c=c||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(b.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new b.Svg("svg").attr({width:c,height:d}).addClass(e),f._node.style.width=c,f._node.style.height=d,a.appendChild(f._node),f},b.normalizeData=function(a,c,d){var e,f={raw:a,normalized:{}};return f.normalized.series=b.getDataArray({series:a.series||[]},c,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,b.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),c&&b.reverseData(f.normalized),f},b.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},b.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},b.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},b.isNumeric=function(a){return null!==a&&isFinite(a)},b.isFalseyButZero=function(a){return!a&&0!==a},b.getNumberOrUndefined=function(a){return b.isNumeric(a)?+a:void 0},b.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},b.getMultiValue=function(a,c){return b.isMultiValue(a)?b.getNumberOrUndefined(a[c||"y"]):b.getNumberOrUndefined(a)},b.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},b.getBounds=function(a,c,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:c.high,low:c.low};k.valueRange=k.high-k.low,k.oom=b.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=b.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&b.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(b.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=b.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},b.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)}},b.createChartRect=function(a,c,d){var e=!(!c.axisX&&!c.axisY),f=e?c.axisY.offset:0,g=e?c.axisX.offset:0,h=a.width()||b.quantity(c.width).value||0,i=a.height()||b.quantity(c.height).value||0,j=b.normalizePadding(c.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"===c.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"===c.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},b.createGrid=function(a,c,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",b.extend({type:"grid",axis:d,index:c,group:g,element:k},j))},b.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})},b.createLabel=function(a,c,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]=c,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=d.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",b.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,b.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",b.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},b.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]},b.optionsProvider=function(a,d,e){function f(a){var f=h;if(h=b.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(c[h/2]));return f}}(this,a),function(a,b){"use strict";b.Interpolation={},b.Interpolation.none=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function(c,d){for(var e=new b.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),b.Svg.Path.join(i)}if(c=h[0].pathCoordinates,g=h[0].valueData,c.length<=4)return b.Interpolation.none()(c,g);for(var j,k=(new b.Svg.Path).move(c[0],c[1],!1,g[0]),l=0,m=c.length;m-2*!j>l;l+=2){var n=[{x:+c[l-2],y:+c[l-1]},{x:+c[l],y:+c[l+1]},{x:+c[l+2],y:+c[l+3]},{x:+c[l+4],y:+c[l+5]}];j?l?m-4===l?n[3]={x:+c[0],y:+c[1]}:m-2===l&&(n[2]={x:+c[0],y:+c[1]},n[3]={x:+c[2],y:+c[3]}):n[0]={x:+c[m-2],y:+c[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+c[l],y:+c[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 b.Interpolation.none()([])}},b.Interpolation.monotoneCubic=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function d(c,e){var f=b.splitIntoSegments(c,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))}),b.Svg.Path.join(g)}if(c=f[0].pathCoordinates,e=f[0].valueData,c.length<=4)return b.Interpolation.none()(c,e);var h,i,j=[],k=[],l=c.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 b.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(b){var h=i.elem("path",{d:b.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:c.normalized.series[g],path:b.clone(),series:e,seriesIndex:g,axisX:d,axisY:f,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:f.bounds,chartRect:j,axisX:d,axisY:f,svg:this.svg,options:a})}function d(a,c,d,f){b.Line["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Line=b.Base.extend({constructor:d,createChart:c})}(this,a),function(a,b){"use strict";function c(a){var c,d;a.distributeSeries?(c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),c.normalized.series=c.normalized.series.map(function(a){return[a]})):c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=b.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var f=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!==c.normalized.series.length){var i=b.serialMap(c.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=b.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=b.getHighLow(c.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=b.createChartRect(this.svg,a,e.padding);k=a.distributeSeries&&a.stackBars?c.normalized.labels.slice(0,1):c.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new b.AutoScaleAxis(b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new b.StepAxis(b.Axis.units.y,c.normalized.series,o,{ticks:k}):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new b.StepAxis(b.Axis.units.x,c.normalized.series,o,{ticks:k}):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new b.AutoScaleAxis(b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&b.createGridBackground(f,o,a.classNames.gridBackground,this.eventEmitter),c.raw.series.forEach(function(d,e){var f,h,i=e-(c.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/c.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/c.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":b.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+b.alphaNumerate(e)].join(" ")),c.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,c.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,c.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,c.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,c.normalized.series[e])},l instanceof b.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=b.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(b.isNumeric).join(","),"ct:meta":b.serialize(w)}),this.eventEmitter.emit("draw",b.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 d(a,c,d,f){b.Bar["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.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"}});b.Bar=b.Base.extend({constructor:d,createChart:c})}(this,a),function(a,b){"use strict";function c(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 d(a){var d,e,g,h,i,j=b.normalizeData(this.data),k=[],l=a.startAngle;this.svg=b.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=b.createChartRect(this.svg,a,f.padding),g=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=b.quantity(a.donutWidth);"%"===m.unit&&(m.value*=g/100),g-=a.donut&&!a.donutSolid?m.value/2:0,h="outside"===a.labelPosition||a.donut&&!a.donutSolid?g:"center"===a.labelPosition?0:a.donutSolid?g-m.value/2:g/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&&(d=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,f){if(0!==j.normalized.series[f]||!a.ignoreEmptyValues){k[f].attr({"ct:series-name":e.name}),k[f].addClass([a.classNames.series,e.className||a.classNames.series+"-"+b.alphaNumerate(f)].join(" "));var p=i>0?l+j.normalized.series[f]/i*360:0,q=Math.max(0,l-(0===f||o?0:.2));p-q>=359.99&&(p=q+359.99);var r,s,t,u=b.polarToCartesian(n.x,n.y,g,q),v=b.polarToCartesian(n.x,n.y,g,p),w=new b.Svg.Path(!a.donut||a.donutSolid).move(v.x,v.y).arc(g,g,0,p-l>180,0,u.x,u.y);a.donut?a.donutSolid&&(t=g-m.value,r=b.polarToCartesian(n.x,n.y,t,l-(0===f||o?0:.2)),s=b.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[f].elem("path",{d:w.stringify()},x);if(y.attr({"ct:value":j.normalized.series[f],"ct:meta":b.serialize(e.meta)}),a.donut&&!a.donutSolid&&(y._node.style.strokeWidth=m.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[f],totalDataSum:i,index:f,meta:e.meta,series:e,group:k[f],element:y,path:w.clone(),center:n,radius:g,startAngle:l,endAngle:p}),a.showLabel){var z;z=1===j.raw.series.length?{x:n.x,y:n.y}:b.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var A;A=j.normalized.labels&&!b.isFalseyButZero(j.normalized.labels[f])?j.normalized.labels[f]:j.normalized.series[f];var B=a.labelInterpolationFnc(A,f);if(B||0===B){var C=d.elem("text",{dx:z.x,dy:z.y,"text-anchor":c(n,z,a.labelDirection)},a.classNames.label).text(""+B);this.eventEmitter.emit("draw",{type:"label",index:f,group:d,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 e(a,c,d,e){b.Pie["super"].constructor.call(this,a,c,f,b.extend({},f,d),e)}var f=(a.window,a.document,{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:b.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1});b.Pie=b.Base.extend({constructor:e,createChart:d,determineAnchorPosition:c})}(this,a),a}); //# sourceMappingURL=chartist.min.js.map \ No newline at end of file diff --git a/dist/chartist.min.js.map b/dist/chartist.min.js.map index 46c5902e..bb606dcf 100644 --- a/dist/chartist.min.js.map +++ b/dist/chartist.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["chartist.js"],"names":["root","factory","define","amd","module","exports","this","Chartist","version","globalRoot","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.1\n * Copyright © 2019 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.1'\n};\n\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, Chartist));\n;/**\n * Chartist path interpolation functions.\n *\n * @module Chartist.Interpolation\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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 (globalRoot, 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}(this, Chartist));\n;/**\n * This module provides some basic prototype inheritance utilities.\n *\n * @module Chartist.Class\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\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}(this, Chartist));\n;/**\n * Chartist SVG module for simple SVG DOM abstraction\n *\n * @module Chartist.Svg\n */\n/* global Chartist */\n(function(globalRoot, Chartist) {\n 'use strict';\n\n var document = globalRoot.document;\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}(this, 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(globalRoot, 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}(this, Chartist));\n;/* global Chartist */\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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","globalRoot","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.3\n * Copyright © 2019 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.3'\n};\n\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, Chartist));\n;/**\n * Chartist path interpolation functions.\n *\n * @module Chartist.Interpolation\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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 (globalRoot, 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}(this, Chartist));\n;/**\n * This module provides some basic prototype inheritance utilities.\n *\n * @module Chartist.Class\n */\n/* global Chartist */\n(function(globalRoot, 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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\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}(this, Chartist));\n;/**\n * Chartist SVG module for simple SVG DOM abstraction\n *\n * @module Chartist.Svg\n */\n/* global Chartist */\n(function(globalRoot, Chartist) {\n 'use strict';\n\n var document = globalRoot.document;\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}(this, 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(globalRoot, 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}(this, Chartist));\n;/* global Chartist */\n(function (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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 (globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist){\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, 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(globalRoot, Chartist) {\n 'use strict';\n\n var window = globalRoot.window;\n var document = globalRoot.document;\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}(this, Chartist));\n\nreturn Chartist;\n\n}));\n"]} \ No newline at end of file diff --git a/package.json b/package.json index dfa98da4..2c6a5fd9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "chartist", "title": "Chartist.js", "description": "Simple, responsive charts", - "version": "0.11.1", + "version": "0.11.3", "author": "Gion Kunz", "homepage": "https://gionkunz.github.io/chartist-js", "repository": { @@ -42,7 +42,6 @@ "dependencies": {}, "devDependencies": { "assemble-dox": "0.0.2", - "chalk": "^2.4.2", "grunt": "^1.0.1", "grunt-assemble": "^0.4.0", "grunt-concurrent": "^2.3.0", @@ -82,8 +81,7 @@ "dev": "./node_modules/.bin/grunt dev", "build": "./node_modules/.bin/grunt build", "preview": "./node_modules/.bin/grunt preview", - "public": "./node_modules/.bin/grunt public", - "postinstall": "node ./rescue-campaign.js" + "public": "./node_modules/.bin/grunt public" }, "config": { "banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> 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", diff --git a/rescue-campaign.js b/rescue-campaign.js deleted file mode 100644 index 867f1168..00000000 --- a/rescue-campaign.js +++ /dev/null @@ -1,11 +0,0 @@ -const chalk = require('chalk'); - -console.log(chalk.red(' CHARTIST NEEDS YOUR HELP!')); -console.log(chalk.yellow(' _____ _ _ _ _')); -console.log(chalk.yellow(' / ____| | | | (_) | |')); -console.log(chalk.yellow('| | | |__ __ _ _ __| |_ _ ___| |_')); -console.log(chalk.yellow('| | | \'_ \\ / _` | \'__| __| / __| __|')); -console.log(chalk.yellow('| |____| | | | (_| | | | |_| \\__ \\ |_ ')); -console.log(chalk.yellow(' \\_____|_| |_|\\__,_|_| \\__|_|___/\\__|')); -console.log(chalk.yellow('Your support will help to save Chartist.')); -console.log(chalk.yellow('https://tinyurl.com/save-chartist')); diff --git a/site/data/pages/index.yml b/site/data/pages/index.yml index 27a3a7f8..20174216 100644 --- a/site/data/pages/index.yml +++ b/site/data/pages/index.yml @@ -1,3 +1,19 @@ +affiliate-projects: + - title: Material Dashboard Pro + link: https://www.creative-tim.com/product/material-dashboard-pro?ref=chartist.io + image: + src: https://s3.amazonaws.com/creativetim_bucket/products/51/original/opt_mdp_thumbnail.jpg + alt: Material Dashboard Pro + - title: Material Dashboard Pro Angular + link: https://www.creative-tim.com/product/material-dashboard-pro-angular2?ref=chartist.io + image: + src: https://s3.amazonaws.com/creativetim_bucket/products/55/original/opt_mdp_angular_thumbnail.jpg + alt: Material Dashboard Pro Angular + - title: Light Bootstrap Dashboard PRO React + link: https://www.creative-tim.com/product/light-bootstrap-dashboard-pro-react?ref=chartist.io + image: + src: https://s3.amazonaws.com/creativetim_bucket/products/66/original/opt_lbdp_react_thumbnail.jpg + alt: Light Bootstrap Dashboard PRO React gallery-examples: - id: example-gallery-one classes: ct-golden-section diff --git a/site/layouts/landing.hbs b/site/layouts/landing.hbs index ef1aa582..fe6bc549 100644 --- a/site/layouts/landing.hbs +++ b/site/layouts/landing.hbs @@ -1,11 +1,6 @@ --- layout: default --- -
    -
    Chartist needs your help! Please, help me save Chartist!
    -

    Do you like Chartist? Then please help me bring it to the next level and make its maintenance more sustainable in the future.

    - Help to save Chartist -
    Chartist.js diff --git a/site/partials/affiliate-project.hbs b/site/partials/affiliate-project.hbs new file mode 100644 index 00000000..73e5b0f2 --- /dev/null +++ b/site/partials/affiliate-project.hbs @@ -0,0 +1,5 @@ + +
    {{title}}
    + {{image.alt}} +
    Get this Template
    +
    diff --git a/site/styles/_affiliate-project.scss b/site/styles/_affiliate-project.scss new file mode 100644 index 00000000..3d929788 --- /dev/null +++ b/site/styles/_affiliate-project.scss @@ -0,0 +1,31 @@ +.affiliate-projects { + display: flex; + margin: 0 -10px; +} + +.affiliate-project { + display: block; + margin: 0 10px; +} + +.affiliate-project__title { + display: block; + font-size: 20px; + font-weight: bold; + margin: 10px 0; + line-height: 1.1; +} + +.affiliate-project__image { + margin-bottom: 10px; +} + +@media screen and (max-width: 640px) { + .affiliate-projects { + display: block; + } + + .affiliate-project { + margin: 10px; + } +} diff --git a/site/styles/_rescue.scss b/site/styles/_rescue.scss deleted file mode 100644 index b8e8db06..00000000 --- a/site/styles/_rescue.scss +++ /dev/null @@ -1,31 +0,0 @@ -@import "http://github.com/settings/chartist-docs"; - -.rescue-chartist { - background-color: $color-red; - color: white; - padding: 20px; -} - -.rescue-title { - font-size: 32px; - font-weight: bold; - text-transform: uppercase; - margin-bottom: 10px; -} - -.rescue-message { - font-size: 20px; -} - -.rescue-button { - color: $color-red; - background-color: white; - font-weight: 300 !important; - &:before { - padding-right: 0.5em; - } - - &:hover, - &:focus { color: $color-red; - background-color: $color-white;} -} diff --git a/site/styles/main.scss b/site/styles/main.scss index f35ae4f0..f8ef8b0b 100644 --- a/site/styles/main.scss +++ b/site/styles/main.scss @@ -17,7 +17,7 @@ @import "http://github.com/api-doc"; @import "http://github.com/live-example"; @import "http://github.com/example-charts"; -@import "http://github.com/rescue"; +@import "http://github.com/affiliate-project"; .button { text-transform: uppercase; diff --git a/site/templates/index.hbs b/site/templates/index.hbs index 88b80648..518f31c2 100644 --- a/site/templates/index.hbs +++ b/site/templates/index.hbs @@ -10,6 +10,14 @@ a community that was disappointed about the abilities provided by other charting of other great charting libraries but after using them there were always tweaks you would have wished for that were not included.

    +

    Get awesome Dashboard Templates by Creative Tim

    +

    Are you planning to use Chartist to create a nice Dashboard or Admin UI? Don't loose any time and kickstart your development using the awesome templates by Creative Tim. They include Chartist and come with awesome chart styles!

    +
    +{{#each page.affiliate-projects}} + {{> affiliate-project }} +{{/each}} +
    +

    Highly customizable responsive charts